在Topic
模型中:
class Topic < ActiveRecord::Base
has_many :choices, :dependent => :destroy
accepts_nested_attributes_for :choices
attr_accessible :title, :choices
end
在POST广告期间,提交的params
为:choices
,而不是Rails预期的:choices_attributes
,并提供错误:
ActiveRecord::AssociationTypeMismatch (Choice(#70365943501680) expected,
got ActiveSupport::HashWithIndifferentAccess(#70365951899600)):
有没有办法让accepts_nested_attributes_for
接受在JSON调用中以choices
而不是choices_attributes
传递的参数?
目前,我在控制器中进行了属性创建(这似乎不是一个优雅的解决方案):
def create
choices = params[:topic].delete(:choices)
@topic = Topic.new(params[:topic])
if choices
choices.each do |choice|
@topic.choices.build(choice)
end
end
if @topic.save
render json: @topic, status: :created, location: @topic
else
render json: @topic.errors, status: :unprocessable_entity
end
end
答案 0 :(得分:0)
您可以在模型中创建方法choices=
def choices=(params)
self.choices_attributes = params
end
但是你会打破选择关联的制定者。
最好的方法是修改表单以返回choices_attributes
而不是choices
答案 1 :(得分:0)
这是一个较旧的问题,但我遇到了同样的问题。还有其他方法吗?看起来“_attributes”字符串在nested_attributes.rb代码(https://github.com/rails/rails/blob/master/activerecord/lib/active_record/nested_attributes.rb#L337)中是硬编码的。
在提交表单时为属性分配“choices_attributes”很好,但是如果它被用于API则会怎样。在那种情况下它只是没有意义。
在为API传递JSON时,有没有人可以绕过这个或替代方案?
感谢。
更新:
好吧,既然我没有听到任何关于此的更新,我将展示我现在如何解决这个问题。作为Rails的新手,我愿意接受建议,但这是我现在能够解决的唯一方法。
我在API base_controller.rb中创建了一个adjust_for_nested_attributes方法
def adjust_for_nested_attributes(attrs)
Array(attrs).each do |param|
if params[param].present?
params["#{param}_attributes"] = params[param]
params.delete(param)
end
end
end
此方法基本上将传入的任何属性转换为#{attr} _attributes,以便它与accepts_nested_attributes_for一起使用。
然后在每个需要此功能的控制器中,我添加了一个像这样的before_action
before_action only: [:create] do
adjust_for_nested_attributes(:choices)
end
现在我只担心创建,但如果你需要更新,你可以将它添加到before_action的'only'子句中。
答案 2 :(得分:0)
# Adds support for creating choices associations via `choices=value`
# This is in addition to `choices_attributes=value` method provided by
# `accepts_nested_attributes_for :choices`
def choices=(value)
value.is_a?(Array) && value.first.is_a?(Hash) ? (self.choices_attributes = value) : super
end