基于多态父 class 的回形针动态样式不起作用(Rails 4.2.5,回形针 4.3.1)

Paperclip dynamic styles based on polymorphic parent class doesn't work (Rails 4.2.5, Paperclip 4.3.1)

基本上我有一个 Image 模型,它 多态性地 属于 imageable,到目前为止 ListItem。由于图像将具有自己的属性和关系,我不想将图像视为 ListItem 的属性并将其搞砸。所以我创建了 Image 模型。

我想要实现的是 List 应该有一个高度等于宽度的徽标缩略图,但 Item 具有不同的样式。 Paperclip 文档告诉我们使用 lambda 创建动态样式。所以这是我的 Image 模型:

class Image < ActiveRecord::Base

  belongs_to :imageable, polymorphic: true

  has_attached_file :file,
                    :styles => lambda { |file| { thumb: (file.instance.imageable_type == "List") ? "300x300!" : "200x100!") } }
                    :default_url => "/images/:style/missing.png"

end

还有我的 List 模特:

class List < ActiveRecord::Base
  def list_params
    params.require(:list).permit(:title, :image_attributes)
  end

  has_one :image, as: :imageable
  accepts_nested_attributes_for :image
  validates :image, presence: true
end

还有我的 lists_controller.rb:

class ListsController < ApplicationController
  def list_params
    params.require(:list).permit(:title, :image_attributes)
  end

  def create
    @list = List.new(list_params)
    if @list.save
      redirect_to @list
    else
      render :action => "new"
    end 
  end
end

而且我在列表的 new.html.erb 中有嵌套表格。 如果我不在 Image 模型中使用动态样式,一切正常。如果我这样做,处理图像样式时 imageable_type 仍然是 nil。人们认为,当与 imageable 相关的所有内容都未分配时,Paperclip 处理器出现得太早了。所以结果是我总是有一个 200x100 大小的图像,即使可成像是 List.

我一直在寻找解决方案。但是许多解决方案适用于 Rails 3,但在我的应用程序中失败了(例如 attr_accessible 解决方案和任何旨在检索有关可成像对象的任何解决方案)。现在,如果有人能在我屈服并使用 STI 或 monkey-patch Active Record 之前提供一个干净的解决方案,我将不胜感激。

monkey-patch 解决方案很好地解释了为什么会发生这种情况。但是如果对Active Record没有全面的了解就不太容易理解。基本上,您必须 Rails 在分配回形针之前分配可成像的相关属性。

感谢@Eren CAY here,我找到了一个更简单的解决方案。但我对其进行了一些修改以使其在我的应用程序中更好地工作。

在我的 Image 模型中:

class Image < ActiveRecord::Base

  belongs_to :imageable, polymorphic: true

  has_attached_file :file,
                    :styles => -> (file) {file.instance.get_customized_styles},
                    :default_url => "/images/:style/missing.png"

  def get_customized_styles
    raise "Imageable not found." unless imageable_type

    if imageable_type == "List"
      imageable_type.constantize.image_styles
    else
      raise "Please define styles for #{imageable_type}."
    end
  end

end

在我的 lists_controller.rb 中:

class ListsController < ApplicationController

  def list_params
    params.require(:list).permit(:title, :description, :image_attributes)
  end

  def new
    @list = List.new
    @list.build_image
  end

  def create
    cleaned_list_params = list_params.dup
    cleaned_list_params.delete(:image_attributes)
    @list = List.new(cleaned_list_params)

    image_params = {imageable_type: "List", file: params[:list][:image_attributes][:file]}
    @list.build_image(image_params)
    if @list.save
      redirect_to :action => "index"
    else
      render :action => "new"
    end
  end

end

我认为最重要的是传递的指定参数告诉Image它的可成像类型(无论参数是字符串还是对象还是其他什么)。通常情况下,只有在文件属性被赋值后,其他可成像相关的属性才被赋值。

与原方案的主要区别在于:

  1. 仅将 字符串 而不是 对象 传递给图像。然后在需要时常量化字符串。
  2. 将 image_styles 存储在 可成像模型 中。我更喜欢这种方式来维护样式而不是将它们全部放在 Image 模型中。
  3. 将强参数传递给 List.new,因为它有自己的属性。 ('clean' 过程是可选的,我只是不想让一大堆 image_attributes 被传递并触发 Paperclip)