我希望我的做法不会让人流血。它可能不是最好的复制代码(对提示感到高兴),但我希望这个想法有帮助(并且确实有效):-p
我有一个庞大的模型元素网络,可用于为任何事物创建“预计划”,从单个建筑物到整个大学校园,其中包含数十个结构、数百个消火栓……而且一个结构可以有各种事物(屋顶、通道(门)、危险材料、火灾探测系统、保护系统、洒水装置等)。
任何元素都可以附加/编辑/删除一张或多张照片。
多态所有者:我喜欢装饰活动跟踪,以显示谁添加/编辑/删除了照片以及“拥有”元素,无论类别如何。
因此,可重复使用的部分用于为任何元素建立一个漂亮的“添加照片”拖放着陆区。部分被传递给一个本地来告诉“拥有”元素是什么(结构,或屋顶,或警报系统):
= render partial: 'photos/photos', locals: {owner: item}
在该部分内部,拥有元素被进一步解析......(可能没有必要,可以将所有者传递并在控制器中将其解析出来,现在我看看它!)
= link_to new_photo_path(:owner_id => owner, :owner_class => owner.class, :tag => owner.class::TAG),
然后控制器有一些动作来处理“拥有”对象......
class PhotosController < ApplicationController
before_action :set_owning_object, only: [:new, :index]
before_action :get_owning_object, only: [:create, :update]
...
def set_owning_object
@owner_class = params["owner_class"]
@owner_id = params["owner_id"]
@photo_tag = params["tag"]
session[:owner_class] = @owner_class if @owner_class
session[:owner_id] = @owner_id if @owner_id
session[:photo_tag] = @photo_tag if @photo_tag
# Unsafe reflection method constantize called with parameter value
# Let's whitelist the allowable classes that can have Photos
if @owner_class
if (%w(Preplan Structure Organization PreplanLayout StagingArea) + Structure::Default_Elements).include? @owner_class
@owning_object = (@owner_class.constantize).find(@owner_id)
else
Rails.logger.warn("OWNING CLASS NEEDS TO BE ADDED: #{@owner_class} was not cleared for use in #{__method__}.")
end
else
@owning_object = nil
end
end
并且控制器使用这个高度多态的“所有者”类(包括包含 public_activity gem 的 HasActivities 模块)在所需的 CRUD 操作下手动添加活动:
def create
authorize Photo
@photo = Photo.new(photo_params)
@photo.tags << @photo_tag
add_photo(@owning_object, @photo)
respond_to do |format|
if @photo.save
if @owning_object.respond_to? :create_activity
@owning_object.create_activity(:add_photo,
owner: view_context.current_user,
organization: view_context.current_org,
recipient: @owning_object,
parameters: { name: @photo.caption, file: @photo.photo_name, owner: @owning_object.name })
end
pseudo_url = owning_object_url(@owning_object)
format.html {
redirect_to pseudo_url, notice: "Photo was successfully added."
}
format.json {render json: { photo: render_to_string(partial: 'photos/photo', layout: false, :formats => [:html], locals: { photo: @photo, photo_counter: @photo.id }) }}
else
format.html {render action: 'new'}
format.json {render json: { error: @photo.errors.full_messages.join(',') }, :status => 406}
end
end
end
def update
authorize @photo
if @photo.update_attributes(photo_params)
@photo.create_activity(:update,
owner: view_context.current_user,
organization: view_context.current_org,
recipient: @owning_object,
parameters: { name: @photo.caption, file: @photo.photo_name })
respond_to do |format|
format.js
end
end
end
def destroy
authorize @photo
@photo.create_activity(key: 'photo.destroy',
owner: current_user,
organization: view_context.current_org,
parameters: { name: @photo.caption, file: @photo.photo_name })
@photo.destroy
respond_to do |format|
format.html {redirect_to :back}
format.json {head :no_content}
end
end
前面提到的 HasActivity 模块:
module HasActivities
extend ActiveSupport::Concern
included do
include PublicActivity::Common
end
end