Ruby On Rails中Create方法重定向报错:无法获取nil类Diary的ID
问题分析
你碰到的问题根源很明确:在create动作里,params[:id]根本不存在,导致Diary.find_by_id(params[:id])返回了nil,后续调用diary.id自然就触发了"undefined method `id' for nil:NilClass"的错误。
毕竟Rails里的create动作对应的是新建资源的POST请求,这类请求的参数里不会带:id——:id只有在操作已有资源的动作(比如show/edit/update)里才会出现。你换成其他页面重定向正常,只是因为那些重定向不需要依赖diary.id而已。
具体解决方案
根据你的业务场景,分两种情况给出修复方案:
场景1:ThreeDigitDraw和Diary是关联关系(比如Pick3属于某个Diary)
如果你的ThreeDigitDraw模型本来就和Diary是关联的,那应该通过关联逻辑来获取对应的Diary,而不是瞎找params[:id]:
- 先确认模型关联定义
确保你的模型里已经配置了正确的关联:
# app/models/three_digit_draw.rb class ThreeDigitDraw < ApplicationRecord belongs_to :diary belongs_to :user end # app/models/diary.rb class Diary < ApplicationRecord has_many :three_digit_draws belongs_to :user end
- 修改create方法
如果创建Pick3的请求是从某个Diary的页面发起的,那你需要在表单里把Diary的ID传过来,然后在create方法里从表单参数里获取:
def create user = current_user # 从表单参数里拿diary_id,而不是找params[:id] diary = Diary.find(params[:three_digit_draw][:diary_id]) # 怕找不到Diary报错的话,也可以用find_by:Diary.find_by(id: params[:three_digit_draw][:diary_id]) # 用user的关联方法build,自动绑定user_id pick3 = user.three_digit_draws.build(three_digit_draw_params) pick3.diary = diary if pick3.save # 现在diary是有效的对象,重定向就不会报错了 redirect_to diary_path(diary), notice: 'Pick3创建成功!' else render :new end end # 别忘了在强参数里允许diary_id private def three_digit_draw_params params.require(:three_digit_draw).permit(:你的字段1, :你的字段2, :diary_id) end
- 在表单里添加隐藏域传递diary_id
在创建Pick3的表单中,加个隐藏域把当前Diary的ID传进去:
# app/views/three_digit_draws/_form.html.erb <%= form_with(model: @three_digit_draw) do |form| %> <!-- 你的其他表单字段 --> <%= form.hidden_field :diary_id, value: @diary.id %> <%= form.submit '创建Pick3' %> <% end %>
场景2:Pick3要关联到当前用户的默认Diary
如果每个用户只有一个Diary,或者你想关联到用户的默认Diary,那直接从current_user里取就行:
def create user = current_user # 获取当前用户的第一个Diary,或者按你的业务逻辑取默认Diary diary = user.diaries.first # 先判断用户有没有Diary,没有的话引导创建 if diary.nil? redirect_to new_diary_path, alert: '你需要先创建一个Diary!' return end pick3 = user.three_digit_draws.build(three_digit_draw_params) pick3.diary = diary if pick3.save redirect_to diary_path(diary), notice: 'Pick3创建成功!' else render :new end end
额外调试小技巧
如果你不确定请求参数里到底有什么,可以在create方法开头加一行调试代码:
def create Rails.logger.debug "当前请求参数:#{params.inspect}" # 其他代码... end
然后查看log/development.log,就能清清楚楚看到哪些参数是存在的,哪些是没有的。
内容的提问来源于stack exchange,提问作者Mikey_Gnote
相关产品推荐
相关产品推荐

