问题
Basically I have an Image
model which polymorphically belongs to imageable
which are by far List
and Item
. Since an image will have its own attribute and relationship, I don't want to treat images like attributes of the List
and Item
and mess it up. So I create the Image
model.
What I want to achieve is that List
should have a logo thumb image where height equals width but Item
has a different style. Paperclip doc has told us to create dynamic styles using lambda
. So here's my Image
model:
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
And my List
model:
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
And my 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
And I have nested form in my new.html.erb
for lists. Everything works well if I don't use dynamic styles in Image
model. If I do so, the imageable_type
remains nil
when the image styles are processed. It is believed that the Paperclip processor comes in too early when everything related to the imageable aren't assigned. So the result is that I always have an image with 200x100
size even when the imageable is a List
.
I've been seeking around for a solution. But many solutions are for Rails 3 and failed in my app (like attr_accessible
solution and any solution intending to retrieve anything about the imageable). Now I'd be grateful if anyone can provide a clean solution before I give in and use STI or monkey-patch Active Record.
回答1:
The monkey-patch solution explains pretty much about why this is happening. But it's not easy to understand if you don't have comprehensive knowledge about Active Record. Basically, you have to make Rails assign imageable related attributes before assigning the Paperclip ones.
I've found a simpler solution thanks to @Eren CAY here. But I made some modifications for it to work better in my app.
In my Image
model:
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
And in my 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
I think the essential is the specified parameter passed to tell Image
its imageable type (no matter the parameter is a string or object or sth else). Normally, it's only after the file attribute is assigned that other imageable related attributes are assigned.
The main differences from the original solution is that:
- Pass only a string rather than a object to image. Then constantize the string if it's needed.
- Store image_styles in imageable models. I prefer this way to maintain the styles rather than put them all in
Image
model. - Pass strong parameters to
List.new
as it has its own attributes. (The 'clean' process is optional, I just don't want the whole bunch of image_attributes to be passed and trigger Paperclip)
来源:https://stackoverflow.com/questions/34361965/paperclip-dynamic-styles-based-on-polymorphic-parent-class-doesnt-work-rails-4