如何便捷为accepts_nested_attributes_for关联子对象设置属性?
解决方案
方法一:直接遍历构建好的关联对象(适合简单嵌套场景)
在控制器创建Garage时,先通过嵌套参数初始化对象,再直接遍历关联的Thing实例设置用户,比操作参数哈希更直观:
def create @garage = Garage.new(safe_garage_params) # 给每个关联的Thing设置用户 @garage.things.each { |thing| thing.user = current_user } @garage.save end def safe_garage_params params.require(:garage).permit(:name, things_attributes: [:id, :name, :_destroy]) end
方法二:递归处理多层嵌套关联(适合复杂多层场景)
如果存在多层嵌套关联(比如Thing还有嵌套的子模型),可以写一个递归方法自动遍历所有嵌套关联对象并设置用户,无需手动处理每一层参数:
def create @garage = Garage.new(safe_garage_params) set_user_on_all_nested_records(@garage, current_user) @garage.save end def safe_garage_params params.require(:garage).permit( :name, things_attributes: [:id, :name, :_destroy, sub_things_attributes: [:id, :content]] # 示例多层嵌套参数 ) end private def set_user_on_all_nested_records(record, user) # 遍历当前模型所有支持嵌套属性的has_many关联 record.class.reflect_on_all_associations(:has_many).each do |assoc| next unless assoc.options[:accepts_nested_attributes_for] record.send(assoc.name).each do |nested_record| # 若嵌套模型有user属性则设置用户 nested_record.user = user if nested_record.respond_to?(:user=) # 递归处理下一层嵌套关联 set_user_on_all_nested_records(nested_record, user) end end end
方法三:模型层关联回调(适合全局统一设置规则)
如果所有通过Garage创建的Thing都需要绑定Garage的创建者,可以在Garage模型的关联上添加before_add回调,把逻辑封装到模型层:
class Garage < ApplicationRecord has_many :things, before_add: :assign_thing_user accepts_nested_attributes_for :things # 假设Garage关联了创建者 belongs_to :creator, class_name: 'User' private def assign_thing_user(thing) thing.user = creator end end
此时控制器只需给Garage绑定创建者即可:
def create @garage = Garage.create(safe_garage_params.merge(creator: current_user)) end def safe_garage_params params.require(:garage).permit(:name, things_attributes: [:id, :name, :_destroy]) end
内容的提问来源于stack exchange,提问作者kwerle
相关产品推荐
相关产品推荐

