Ruby on Rails - Paperclip and dynamic parameters

前端 未结 3 1785
长情又很酷
长情又很酷 2021-02-04 15:24

I\'m writing some image upload code for Ruby on Rails with Paperclip, and I\'ve got a working solution but it\'s very hacky so I\'d really appreciate advice on how to better imp

3条回答
  •  有刺的猬
    2021-02-04 16:08

    I ran into the same Paperclip chicken/egg issue on a project trying to use dynamic styles based on the associated model with a polymorphic relationship. I've adapted my solution to your existing code. An explanation follows:

    class Asset < ActiveRecord::Base
      attr_accessible :image, :deferred_image
      attr_writer :deferred_image
    
      has_attached_file :image,
        :styles => lambda { |a| a.instance.styles }
    
      belongs_to :project
    
      after_save :assign_deferred_image
    
      def styles
        project.generators.each_with_object({}) { |g, hsh| hsh[g.sym] = "#{g.width}x#{g.height}" }
      end
    
      private
      def assign_deferred_image
        if @deferred_image
          self.image = @deferred_image
          @deferred_image = nil
          save!
        end
      end
    end
    

    Basically, to get around the issue of Paperclip trying to retrieve the dynamic styles before the project relation information has been propagated, you can assign all of the image attributes to a non-Paperclip attribute (in this instance, I have name it deferred_image). The after_save hook assigns the value of @deferred_image to self.image, which kicks off all the Paperclip jazz.

    Your controller becomes:

    # AssetsController
    def create
      @project = Project.find(params[:project_id])
      @asset = @project.assets.build(params[:asset])
      @asset.uploaded_by = current_user
    
      respond_to do |format|
        # all this is unrelated and can stay the same
      end
    end
    

    And the view:

    <%= form_for @asset do |f| %>
      <%# other asset attributes %>
      <%= f.label :deferred_upload %>
      <%= f.file_field :deferred_upload %>
      <%= f.submit %>
    <% end %>
    

    This solution also allows using accepts_nested_attributes for the assets relation in the Project model (which is currently how I'm using it - to upload assets as part of creating/editing a Project).

    There are some downsides to this approach (ex. validating the Paperclip image in relation to the validity of the Asset instance gets tricky), but it's the best I could come up with short of monkey patching Paperclip to somehow defer execution of the style method until after the association information had been populated.

    I'll be keeping an eye on this question to see if anyone has a better solution to this problem!


    At the very least, if you choose to keep using your same solution, you can make the following stylistic improvement to your Asset#styles method:

    def styles
      (@generators || project.generators).each_with_object({}) { |g, hsh| hsh[g.sym] = "#{g.width}x#{g.height}" }
    end
    

    Does the exact same thing as your existing method, but more succinctly.

提交回复
热议问题