Ruby on Rails - 回形针和动态参数 [英] Ruby on Rails - Paperclip and dynamic parameters

查看:43
本文介绍了Ruby on Rails - 回形针和动态参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Paperclip 为 Ruby on Rails 编写一些图像上传代码,我有一个可行的解决方案,但它非常笨拙,因此我非常感谢有关如何更好地实现它的建议.我有一个包含有关上传图像的信息的资产"类,包括回形针附件,以及一个封装尺寸信息的生成器"类.每个项目"都有多个资产和生成器;应根据每个生成器指定的大小调整所有资产的大小;因此,每个项目都有其所有资产应具有的特定大小集.

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 implement it. I have an 'Asset' class containing information about the uploaded images including the Paperclip attachment, and a 'Generator' class that encapsulates sizing information. Each 'Project' has multiple assets and generators; all Assets should be resized according to the sizes specified by each generator; each Project therefore has a certain set of sizes that all of its assets should have.

发电机型号:

class Generator < ActiveRecord::Base
  attr_accessible :height, :width

  belongs_to :project

  def sym
    "#{self.width}x#{self.height}".to_sym
  end
end

资产模型:

class Asset < ActiveRecord::Base
  attr_accessible :filename,
    :image # etc.
  attr_accessor :generators

  has_attached_file :image,
    :styles => lambda { |a| a.instance.styles }

  belongs_to :project

  # this is utterly horrendous
  def styles
    s = {}
    if @generators == nil
      @generators = self.project.generators
    end

    @generators.each do |g|
      s[g.sym] = "#{g.width}x#{g.height}"
    end
    s
  end
end

资产控制器创建方法:

  def create
    @project = Project.find(params[:project_id])
    @asset = Asset.new
    @asset.generators = @project.generators
    @asset.update_attributes(params[:asset])
    @asset.project = @project
    @asset.uploaded_by = current_user

    respond_to do |format|
      if @asset.save_(current_user)
        @project.last_asset = @asset
        @project.save

        format.html { redirect_to project_asset_url(@asset.project, @asset), notice: 'Asset was successfully created.' }
        format.json { render json: @asset, status: :created, location: @asset }
      else
        format.html { render action: "new" }
        format.json { render json: @asset.errors, status: :unprocessable_entity }
      end
    end
  end

我遇到的问题是鸡蛋问题:新创建的资产在正确实例化之前不知道要使用哪个生成器(大小规格).我尝试使用 @project.assets.build,但是在 Asset 设置其项目关联之前仍然执行 Paperclip 代码并且将其清除.

The problem I am having is a chicken-egg issue: the newly created Asset doesn't know which generators (size specifications) to use until after it's been instantiated properly. I tried using @project.assets.build, but then the Paperclip code is still executed before the Asset gets its project association set and nils out on me.

'if @generators == nil' hack 是为了使 update 方法无需进一步修改控制器即可工作.

The 'if @generators == nil' hack is so the update method will work without further hacking in the controller.

总而言之,感觉很糟糕.任何人都可以建议如何以更明智的方式编写此内容,或者甚至可以针对此类事情采取一种方法吗?

All in all it feels pretty bad. Can anyone suggest how to write this in a more sensible way, or even an approach to take for this kind of thing?

提前致谢!:)

推荐答案

我在尝试使用基于具有多态关系的关联模型的动态样式的项目中遇到了相同的 Paperclip 鸡/蛋问题.我已经根据您现有的代码调整了我的解决方案.解释如下:

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

基本上,要解决 Paperclip 在传播项目关系信息之前尝试检索动态样式的问题,您可以将所有 image 属性分配给非 Paperclip 属性(在这个实例,我把它命名为 deferred_image).after_save 钩子将 @deferred_image 的值分配给 self.image,这将启动所有 Paperclip 爵士乐.

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.

您的控制器变为:

# 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

和视图:

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

此解决方案还允许将 accepts_nested_attributes 用于 Project 模型中的 assets 关系(这是我目前使用它的方式 -上传资产作为创建/编辑项目的一部分).

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).

这种方法有一些缺点(例如,验证回形针 imageAsset 实例的有效性相关变得棘手),但这是我能做到的最好的想出没有猴子修补 Paperclip 以某种方式将 style 方法的执行推迟到关联信息填充之后.

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!

至少,如果您选择继续使用相同的解决方案,您可以对 Asset#styles 方法进行以下风格改进:

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.

这篇关于Ruby on Rails - 回形针和动态参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆