基于多态父 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
,到目前为止 List
和 Item
。由于图像将具有自己的属性和关系,我不想将图像视为 List
和 Item
的属性并将其搞砸。所以我创建了 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
它的可成像类型(无论参数是字符串还是对象还是其他什么)。通常情况下,只有在文件属性被赋值后,其他可成像相关的属性才被赋值。
与原方案的主要区别在于:
- 仅将 字符串 而不是 对象 传递给图像。然后在需要时常量化字符串。
- 将 image_styles 存储在 可成像模型 中。我更喜欢这种方式来维护样式而不是将它们全部放在
Image
模型中。
- 将强参数传递给
List.new
,因为它有自己的属性。 ('clean' 过程是可选的,我只是不想让一大堆 image_attributes 被传递并触发 Paperclip)
基本上我有一个 Image
模型,它 多态性地 属于 imageable
,到目前为止 List
和 Item
。由于图像将具有自己的属性和关系,我不想将图像视为 List
和 Item
的属性并将其搞砸。所以我创建了 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
它的可成像类型(无论参数是字符串还是对象还是其他什么)。通常情况下,只有在文件属性被赋值后,其他可成像相关的属性才被赋值。
与原方案的主要区别在于:
- 仅将 字符串 而不是 对象 传递给图像。然后在需要时常量化字符串。
- 将 image_styles 存储在 可成像模型 中。我更喜欢这种方式来维护样式而不是将它们全部放在
Image
模型中。 - 将强参数传递给
List.new
,因为它有自己的属性。 ('clean' 过程是可选的,我只是不想让一大堆 image_attributes 被传递并触发 Paperclip)