虚拟属性未移动到params内的模型哈希

时间:2012-02-19 22:54:42

标签: ruby-on-rails-3 virtual-attribute

我在Rails 3.2应用程序中遇到问题,其中通过JSON重新发送的虚拟属性不在params散列中的正确位置。嗯,这不是我所期待的。我的期望是否正确还有待观察。 :)

我有一个使用标准虚拟属性模式的模型,如下所示:

class Track < ActiveRecord::Base
  def rating
    # get logic removed for brevity
  end

  def rating=(value)
    # set logic
  end

  def as_json(options={}) # so my method is in the JSON when I use respond_with/to_json
    super(options.merge(methods: [:rating]))
  end
end

发送到我的控制器的JSON如下所示:

{"id":1,"name":"Icarus - Main Theme 2","rating":2}

要明确,名称和ID不是虚拟的,评级是。

我在params hash中得到了这个结果,在rails完成了它的魔力之后:

{"id"=>"1", "name"=>"Icarus - Main Theme 2", "rating"=>2, "track"=>{"id"=>"1", "name"=>"Icarus - Main Theme 2"}}

正如您所看到的,id和name使其成为嵌套的:track散列,但是rating不会。这是预期的行为吗?它打破了(在某种程度上)在控制器中使用嵌套哈希的标准做法,因为嵌套哈希不包含我需要的所有参数。

Track.update(params[:id], params[:track]) # :track is missing rating

感谢您的帮助!

3 个答案:

答案 0 :(得分:7)

我最近遇到了这个陷阱。问题是,params包装器正在查看你的模型Track.attribute_names,以确定如何将数据映射到:track =&gt; {params}哈希。如果没有关联的模型,默认情况下将根据控制器名称包装params,并包含所有值:

class SinglesController < ApplicationController
  def create
    #params[:single] will contain all of your attributes as it doesn't 
    # have an activerecord model to look at.
    @track_single = Track.new(params[:single]) 
  end
end

您可以在控制器中调用wrap_parameters来告诉动作控制器在包装params时要包含哪些属性,如下所示:

class TracksController < ApplicationController
  wrap_parameters :track, :include => :rating
  #other controller stuff below
end

在此处查看更多内容:http://api.rubyonrails.org/classes/ActionController/ParamsWrapper.html

答案 1 :(得分:0)

也许如果你在嵌套哈希中分配rating虚拟属性,如下所示:

def as_json(options={})
  super(options.merge(:track => {:methods => @rating}))
end

它会按照您的预期行事。

答案 2 :(得分:0)

刚遇到这个问题并想出了一个相当不错的解决方案。将以下内容添加到ApplicationController

wrap_parameters exclude: [:controller, :action, :format] + ActionController::ParamsWrapper::EXCLUDE_PARAMETERS

这样,一切都嵌套在你的资源下(除了Rails添加到params哈希的东西),你不必再次附加到一个控制器特定的wrap_parameters调用。 :d