Rails技术问题:如何将一个Model的属性赋值给另一个Model
解决Rails中Model无法访问current_user及关联查询复用表单字段的问题
首先,咱们先明确错误的根源:current_user是Devise提供给控制器层面的方法,用于获取当前会话的登录用户,你的Goal模型实例是无法直接访问这个方法的——这就是你遇到NameError的核心原因。另外,我注意到你的User模型里有个关联小错误:has_one :goals应该改成has_one :goal(has_one关联对应的是单数模型名,这样关联关系才能正确建立)。
接下来,咱们用关联查询的思路来解决复用Waterusage字段的问题,分两步走:
1. 修正模型关联与调整属性复制方法
先把User模型里的关联改对,然后让Goal模型通过自身的用户关联来获取Waterusage数据,不再依赖外部的current_user:
# app/models/user.rb class User < ApplicationRecord # Include default devise modules devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable has_one :waterusage, dependent: :destroy has_one :goal, dependent: :destroy # 这里改成单数:goal,匹配模型名 end # app/models/goal.rb class Goal < ApplicationRecord belongs_to :user # 从关联用户的waterusage中复制属性 def copy_from_waterusage return unless user&.waterusage.present? # 复制所有相同字段,排除不需要的系统字段 self.attributes = user.waterusage.attributes.except( 'id', 'user_id', 'created_at', 'updated_at' ) # 如果只需要复制特定字段,可以逐个指定: # self.household_size = user.waterusage.household_size # self.daily_water_target = user.waterusage.daily_water_target end end
2. 在控制器中调用复制方法
在GoalsController的new动作里,利用当前用户的关联初始化Goal并触发属性复制:
# app/controllers/goals_controller.rb class GoalsController < ApplicationController before_action :authenticate_user! # 确保用户已登录,Devise提供的方法 def new @goal = current_user.build_goal # 通过关联构建Goal,自动绑定current_user @goal.copy_from_waterusage # 调用复制方法,复用Waterusage的字段值 end def create @goal = current_user.build_goal(goal_params) if @goal.save redirect_to dashboard_path, notice: '目标创建成功!' else render :new end end private def goal_params # 允许需要的字段,根据你的表单实际字段调整 params.require(:goal).permit(:household_size, :daily_water_target, :other_fields) end end
为什么这样可行?
- 当你用
current_user.build_goal时,@goal已经自动关联了current_user,所以Goal模型里的user属性是有效的,能通过user.waterusage直接关联查询到用户已填写的用水数据。 - 把属性复制逻辑放在模型里,但依赖的是模型自身的关联关系,而非外部控制器方法,这更符合Rails的MVC设计原则——模型负责数据逻辑,控制器处理会话与请求。
内容的提问来源于stack exchange,提问作者ezweizig
相关产品推荐
相关产品推荐

