【问题标题】:Rails: ActiveModel Error when creating new recordRails:创建新记录时出现 ActiveModel 错误
【发布时间】:2017-10-12 10:09:59
【问题描述】:

我有一个控制器(患者)将患者 ID 传递给另一个控制器(referral_requests)以用于构建转诊请求记录。尝试创建推荐请求时遇到以下错误。我究竟做错了什么?我的 refer_requests 表包含一个用于 user_id 的整数列。

我有多个用枚举定义的用户类型。员工用户创建患者和转诊请求。

感谢您的帮助!

错误:

(0.1ms)  rollback transaction
#<ActiveModel::Errors:0x007fe696696fc0 @base=#<ReferralRequest id: nil, content: nil, user_id: nil, created_at: nil, updated_at: nil, patient_id: 4, call_option_1: nil, call_option_2: nil, call_option_3: nil, call_option_1_status: nil, call_option_2_status: nil, call_option_3_status: nil, status: "created">, @messages={:user_id=>["can't be blank"]}, @details={:user_id=>[{:error=>:blank}]}>

患者控制器创建操作:

def create
  @patient = current_user.patients.build(patient_params)
  if @patient.save
    flash[:success] = "Patient Created!"
    redirect_to new_referral_request_path(patient_id: @patient.id)
  else
    Rails.logger.info(@patient.errors.inspect)
    render 'patients/new'
end

referral_requests 控制器新建和创建操作,以及参数:

def new
  @patient = Patient.find(params[:patient_id]) 
  @referral_request = current_user.referral_requests.build(patient:  @patient) if signed_in?
end

def create
  @referral_request = current_user.referral_requests.build(referral_request_params)
  if @referral_request.save
        flash[:success] = "Referral Request Created!"
        redirect_to new_dispatch_path(referral_request_id:   @referral_request.id)
  else
    Rails.logger.info(@referral_request.errors.inspect)
    @feed_items = []
    render 'static_pages/home'
  end
end

private

def referral_request_params
  params.require(:referral_request).permit(:content, :user_id, :patient_id, concern_ids: [], insurance_ids: [], race_ids: [], language_ids: [], gender_ids: [])
end

以下是模型关系:

require 'active_support/concern'

module StaffUser
  extend ActiveSupport::Concern

  included do
    has_many :referral_requests, foreign_key: "user_id"

class ReferralRequest < ApplicationRecord
  belongs_to :user, -> { where role: :staff }, class_name: 'User', foreign_key: 'user_id'

【问题讨论】:

    标签: ruby-on-rails activemodel


    【解决方案1】:

    如果您要为患者创建转诊,则应将其设为嵌套资源:

    resources :patients do
      resources: :referral_requests, shallow: true
    end
    

    由于创建此资源需要身份验证,因此您需要确保在前置过滤器中进行处理:

    class ReferralRequestsController < ApplicationController
      before_action :authenticate_user!
    end
    

    如果您使用自己的身份验证解决方案而不是使用 Devise,请确保您有这样的方法:

    class ApplicationController
      private
      def authenticate_user!
        redirect_to new_session_path and return unless current_user
      end
    end
    

    当我们创建资源注释时,我们没有从表单输入中获取user_id(由会话提供)或患者 ID(我们从路径段中获取)。

    class ReferralRequestsController < ApplicationController
      before_action :authenticate_user!
      before_action :set_patient, only: [:new, :create, :index]
    
      # GET /patients/:patient_id/referral_requests/new
      def new
        @referral_request = @patient.referral_requests.new
      end
    
      # POST /patients/:patient_id/referral_requests
      def create
        @referral_request = @patient.referral_requests.new(referral_request_params) do |rr|
          rr.user = current_user
        end
    
        if @referral_request.save
          flash[:success] = "Referral Request Created!"
          redirect_to new_dispatch_path(referral_request_id:   @referral_request.id)
        else 
          Rails.logger.info(@referral_request.errors.inspect)
          @feed_items = []
          render :new
        end
      end
    
      private
      def set_patient
        @patient = Patient.find(params[:patient_id])
      end
    
      def referral_request_params
         params.require(:referral_request)
            .permit(:content, 
               concern_ids: [], 
               insurance_ids: [], 
               race_ids: [], 
               language_ids: [], 
               gender_ids: []
            )
      end
    end
    

    在此处使用 before 过滤器还将验证患者是否存在,因为 Patient.find(params[:patient_id]) 将引发 ActiveRecord::RecordNotFound

    使用用户输入和其他值(例如会话中的用户 ID)创建记录的一个好方法是传递一个块:

    @referral_request = @patient.referral_requests.new(referral_request_params) do |rr|
      rr.user = current_user
    end
    

    允许表单中的user_id 参数将使恶意用户可以通过使用网络检查器更改输入来传递任何用户ID!

    您通过传递一个数组在表单中创建正确的路径:

    <%= form_for([@patient, @referral_request]) do |f| %>
    

    【讨论】:

    • 谢谢 Max - 与 shallow: true 一致,您是否打算使用referral_requests 而不是推荐人?我只是想确保没有一些我不理解的别名发生。
    • 是的,应该是resources: :referral_requests, shallow: true
    • 这很有帮助 - 为什么参数中不包含 patient_id?
    • 因为它是路径的一部分。你发帖到/patients/:patient_id/referrals
    • 所以它是参数的一部分 - 但不是表单参数。
    【解决方案2】:

    “user_id”不应出现在您的允许参数列表中。

    编辑:

    cmets 的实际问题是他正在验证“user_id”而不是“user”的存在。通过关联创建记录时,id 将在过程的后期才会填写,因此您只需检查关联项目的存在而不是 id:

    validates :user, presence: true
    

    【讨论】:

    • 我刚刚删除了,但仍然出现同样的错误 - 我想我添加了它希望能解决它。
    • 当我在推荐请求控制器的 create 方法中保存推荐请求之前添加调试器时,我可以看到当我调用推荐请求时 user_id 为 nil 但 current_user 似乎正在工作返回当前用户。
    • 要明确 - 我正在对需要存在 user_id 的推荐请求执行模型验证。我只是不明白为什么它没有被传递到推荐请求,即使 current_user 评估得很好。
    • 您的问题是强制“user_id”出现。您需要验证“用户”的存在。
    猜你喜欢
    • 2019-06-28
    • 1970-01-01
    • 1970-01-01
    • 2016-06-15
    • 1970-01-01
    • 2016-07-13
    • 1970-01-01
    • 2021-10-20
    • 2016-07-29
    相关资源
    最近更新 更多