如何修复Rails中**form_with**标记未向params提交关联模型属性的错误



我有UserUserActivityActivity三个模型。我已经在它们之间创建了一个关联,当我通过它的表单提交值时,我可以在控制台的后面看到这些值,但我会收到空字段的验证错误。

我尝试了几种方法,包括搜索不同的论坛和尝试不同的建议,但都无济于事。

模型

class User < ApplicationRecord
belongs_to :role #, foreign_key: "id"
has_many :user_activities, inverse_of: :user
has_many :activities, through: :user_activities
accepts_nested_attributes_for :user_activities
end
class UserActivity < ApplicationRecord
belongs_to :user, inverse_of: :user_activities
belongs_to :activity, inverse_of: :user_activities, optional: true
attr_accessor :user_activity_date, :user_activity_start,  :user_activity_end, :user_activity_note, :activity_id, :user_id
validates_presence_of :user_activity_end, presence: true, null: false, :message => "cannot be empty"
validates_presence_of :user_activity_start, presence: true, null: false, :message => "cannot be empty"
validates_presence_of :user_activity_date, presence: true, null: false, :message => "cannot be empty"
validates_presence_of :user_activity_note, presence: true, length: { minimum: 10 }, null: false, :message => "cannot be empty"
end
class Activity < ApplicationRecord
has_many :user_activities, inverse_of: :activity
has_many :users, through: :user_activities
accepts_nested_attributes_for :user_activities
end

控制器方法

class UserActivitiesController < ApplicationController
# GET /user_activities/new
def new
@user_activity = current_user.user_activities.build(activity_id: params[:activity_id])
@activity = Activity.all
end
end
# POST /user_activities
# POST /user_activities.json
def create
@user_activity = current_user.user_activities.build
respond_to do |format|
if @user_activity.save
format.html { redirect_to @user_activity, notice: 'User activity was successfully created.' }
format.json { render :show, status: :created, location: @user_activity }
else
@activities = Activity.all
format.html { render :new }
format.json { render json: @user_activity.errors, status: :unprocessable_entity }
end
end
end
def user_activity_params
params.require(:user_activity).permit( :user_activity => [:activity_id, :user_activity_date, :user_activity_start, :user_activity_end, :user_activity_note])
end
end

视图

我删除了一些字段,只是为了减少代码的行数

<%= form_with(model: user_activity, local: true) do |frm| %>
<div class="field">
<%= frm.label :activity_id %><br />
<%= collection_select(:user_activity, :activity_id, Activity.all, :id, :activity_name, prompt: true) %>
<%#= select("user_activity", "activity_id", Activity.all.collect {|a| [ a.activity_name, a.id ] }, {include_blank: 'none'}) %>
</div>
<div class="field">
<%= frm.label(get_user_activity_date) %><br />
<%= frm.date_field :user_activity_date, autofocus: true%>
</div>
<% end %>

控制台上的结果

Started POST "/user_activities" for 127.0.0.1 at 2019-01-16 04:10:28 +0100
Processing by UserActivitiesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"o81mDoZ87/hodGpWaHkH/CDs87Hr2nH+s518GCp8q3GZC650UrRh0hYTCu41ax3vjUhgRC3JkP03ZHbVIYYQJQ==", "user_activity"=>{"activity_id"=>"", "user_activity_date"=>"", "user_activity_start"=>"", "user_activity_end"=>"", "user_activity_note"=>"a test message I place here""}, "commit"=>"Create User activity"}

我原以为提交的表单数据会传递给控制器中的user_activity_params,但后来却没有,因为它不断返回表单中所有字段都为空的错误消息。

FireFox中的错误消息

4 errors prohibited this user_activity from being saved:
User activity end cannot be empty
User activity start cannot be empty
User activity date cannot be empty
User activity note cannot be empty

因此,我无法将数据保存到数据库中的user_activitys表中。

更新服务器日志

Started POST "/user_activities" for 127.0.0.1 at 2019-01-16 21:15:48 +0100
Processing by UserActivitiesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"7v79xk6TW0IHNjkno+iXwzIYqqBjBMxCSodddPHUmKI/N4C9W6nkFz7qApXaQMEFJL6Qumn6BfsX/gxueMjp2w==", "user_activity"=>{"activity_id"=>"1", "user_activity_date"=>"2019-01-15", "user_activity_start"=>"20:14", "user_activity_end"=>"21:15", "user_activity_note"=>"testing to see if values can be retrieved"}, "commit"=>"Create User activity"}
Activity ID -> 1
Date -> 2019-01-15
Start Time -> 20:14
End Time -> 21:15
Activity Note -> testing to see if values can be retrieved
User Load (0.9ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 ORDER BY `users`.`id` ASC LIMIT 1
↳ app/controllers/user_activities_controller.rb:46
(0.5ms)  BEGIN
↳ app/controllers/user_activities_controller.rb:46
UserActivity Create (3.0ms)  INSERT INTO `user_activities` (`created_at`, `updated_at`, `user_id`) VALUES ('2019-01-16 20:15:49', '2019-01-16 20:15:49', 1)
↳ app/controllers/user_activities_controller.rb:46
(0.5ms)  ROLLBACK
↳ app/controllers/user_activities_controller.rb:46
Completed 500 Internal Server Error in 125ms (ActiveRecord: 12.4ms)
ActiveRecord::NotNullViolation (Mysql2::Error: Field 'user_activity_date' doesn't have a default value: INSERT INTO `user_activities` (`created_at`, `updated_at`, `user_id`) VALUES ('2019-01-16 20:15:49', '2019-01-16 20:15:49', 1)):
app/controllers/user_activities_controller.rb:46:in `create'

问题出在strong_parameters方法中。API并不是最直观的。#require方法只返回所需密钥的值。因此,当您转到#permit的某些属性时,您不能告诉它再次查找:user_activity键。

你可以试着在rails控制台上玩一玩,看看会发生什么。首先让我们模拟一组参数:

>> params = ActionController::Parameters.new("user_activity"=>{"user_activity_note"=>"a test message I place here"})
#> <ActionController::Parameters {"user_activity"=>{"user_activity_note"=>"a test message I place here"}} permitted: false>

require返回ActionController::Parameters对象,该对象仅具有所需密钥的值:

>> params.require(:user_activity)
#> <ActionController::Parameters {"user_activity_note"=>"a test message I place here"} permitted: false>

如果我们在permit操作中重复:user_activity键,我们会得到一个空的params对象,因为其中的所有内容都被确定为不允许。这并不是悄无声息地发生的;如果你检查日志,你会发现你的所有属性都是不允许的。

>> params.require(:user_activity).permit(:user_activity => [:user_activity_note])
Unpermitted parameters: :user_activity_note
#> <ActionController::Parameters {} permitted: true>

但如果我们只列出我们需要的属性,我们就会得到预期的结果:

>> params.require(:user_activity).permit(:user_activity_note)
#> <ActionController::Parameters {"user_activity_note"=>"a test message I place here"} permitted: true>

user_activity_params方法更改为:

def user_activity_params
params.require(:user_activity).permit(:activity_id, :user_activity_date, :user_activity_start, :user_activity_end, :user_activity_note)
end

它应该对你有用。

在尝试了大多数没有解决方案的建议后,我修复了收到的错误。我首先查看了模型关联,并相继禁用了一些方法,如inverte_of、accepts_nested_attribute_for和attr_accessor。

之前

class UserActivity < ApplicationRecord
# ----ASSOCIATION OF MODELS----
# a UserActivity belongs to a User
# and UserActivity belongs to an Activity
belongs_to :user, inverse_of: :user_activities
belongs_to :activity, optional: true, inverse_of: :user_activities 
attr_accessor :user_activity_date, :user_activity_start,  :user_activity_end, :user_activity_note, :activity_id, :user_id
accepts_nested_attributes_for :activity, :user
# ----MODEL VALIDATIONS----
validates_presence_of :user_activity_end, presence: true, null: false, :message => "cannot be empty"
validates_presence_of :user_activity_start, presence: true, null: false, :message => "cannot be empty"
validates_presence_of :user_activity_date, presence: true, null: false, :message => "cannot be empty"
validates_presence_of :user_activity_note, presence: true, length: { minimum: 10 }, null: false, :message => "cannot be empty"
validates :user, presence: true
validates :activity, presence: true
end

之后

class UserActivity < ApplicationRecord
# ----ASSOCIATION OF MODELS----
# a UserActivity belongs to a User
# and UserActivity belongs to an Activity
belongs_to :user, inverse_of: :user_activities
belongs_to :activity, optional: true, inverse_of: :user_activities 
accepts_nested_attributes_for :activity, :user
# ----MODEL VALIDATIONS----
validates_presence_of :user_activity_end, presence: true, null: false, :message => "cannot be empty"
validates_presence_of :user_activity_start, presence: true, null: false, :message => "cannot be empty"
validates_presence_of :user_activity_date, presence: true, null: false, :message => "cannot be empty"
validates_presence_of :user_activity_note, presence: true, length: { minimum: 10 }, null: false, :message => "cannot be empty"
validates :user, presence: true
validates :activity, presence: true
end

控制台结果

Started POST "/user_activities" for 127.0.0.1 at 2019-01-18 02:11:27 +0100
Processing by UserActivitiesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Z6DP3METaYH2oczN11Mpewy4K4E1Gj+24twDM4NHI0y2abKn1CnW1M9993+u+3+9Gh4Rmz/k9g+/pVIpCltSNQ==", "user_activity"=>{"activity_id"=>"2", "user_activity_date"=>"2018-12-18", "user_activity_start"=>"09:56", "user_activity_end"=>"11:00", "user_activity_note"=>"still testing for errors in the app"}, "commit"=>"Create User activity"}
The activity ID which is received is -> 2
Date -> 2018-12-18
Start Time -> 09:56
End Time -> 11:00
Activity Note -> still testing for errors in the app
User Load (0.7ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 ORDER BY `users`.`id` ASC LIMIT 1
↳ app/controllers/user_activities_controller.rb:54
(0.4ms)  BEGIN
↳ app/controllers/user_activities_controller.rb:57
UserActivity Create (0.7ms)  INSERT INTO `user_activities` (`user_activity_date`, `user_activity_start`, `user_activity_end`, `user_activity_note`, `created_at`, `updated_at`, `user_id`, `activity_id`) VALUES ('2018-12-18 00:00:00', '09:56:00', '11:00:00', 'still testing for errors in the app', '2019-01-18 01:11:28', '2019-01-18 01:11:28', 1, 2)
↳ app/controllers/user_activities_controller.rb:57
(0.4ms)  COMMIT
↳ app/controllers/user_activities_controller.rb:57
Redirected to http://localhost:3000/user_activities/7
Completed 302 Found in 111ms (ActiveRecord: 4.3ms)

我在UserActivity模型上使用了accepts_nested_attribute_for,并且使用的变量与其已设置的属性完全相同,因此它们存在冲突。

在我禁用它之后,我就可以保存到数据库中,现在一切都很好

我感谢你们的支持,因为他们让我知道了在哪里使用我的错误查找技术。

最新更新