我已经研究过类似的问题,但是我不觉得他们已经解决了我的特定问题: Rails form_for results in POST instead of PUT when trying to edit
form_for with nested resources
我是Rails的新手(使用Rails 4.2.5),我正在尝试我的第一个应用程序。我的问题有两个方面:(1)当用户去编辑用户故事时,表单的字段不会填充先前输入的数据(2)重新提交表单时,会创建一个新条目,而不是编辑旧条目数据
我觉得user_stories/edit.html.erb
的form_for就是问题所在。当我从表单中取出.build
方法时,我收到以下错误消息:
未定义的方法`to_key' for #UserStory :: ActiveRecord_Associations_CollectionProxy:0x007f456a759138>
我项目视图的projects/_form.html.erb
没有正确的.build
方法和功能。但是,我可以使`user_stories / _form.html.erb表单工作的唯一方法是附加构建方法。
这是我的代码:
user_story.rb
class UserStory < ActiveRecord::Base
belongs_to :project
belongs_to :user
include RankedModel
ranks :row_order
end
project.rb
class Project < ActiveRecord::Base
has_many :user_stories
belongs_to :user
end
的routes.rb
Rails.application.routes.draw do
devise_for :users
resources :projects do
resources :user_stories
end
end
resources :user_stories do
post :update_row_order, on: :collection
end
root 'welcome#index'
end
user_stories / _form.html.erb
<%= form_for([@project, @user_story.build]) do |f| %>
<div class="form-group">
<p>As a ...</p>
<%= f.text_field :param1, placeholder: "type of user", class: "form-control" %>
</div>
<div class="form-group">
<p>I want ...</p>
<%= f.text_field :param2, placeholder: "desired functionality", class: "form-control" %>
</div>
<div class="form-group">
<p>so that...</p>
<%= f.text_field :param3, placeholder: "reason for desired functionality", class: "form-control" %>
</div>
<div class="actions">
<%= f.submit class: "btn btn-primary" %>
</div>
<% end %>
user_stories_controller.rb
class UserStoriesController < ApplicationController
before_action :set_project
before_action :set_user_story, except: [:create]
def index
@user_story = @project.user_stories.rank(:row_order).all
end
def update_row_order
@user_story.row_order_position = user_story_params[:row_order_position]
@user_story.save
render nothing:true # this is a POST action, updates sent via AJAX, no view rendered
end
def create
@user_story = @project.user_stories.create(user_story_params)
redirect_to @project
end
def new
end
def destroy
if @user_story.destroy
flash[:success] = "User story deleted"
else
flash[:error] = "User story could not be deletd"
end
redirect_to @project
end
def complete
user_story.update_attribute(completed_at, Time.now)
redirect_to @project, notice: "User story completed functionality complete"
end
def update
respond_to do |format|
if @project.user_stories.update(@project, user_story_params)
format.html { redirect_to project_path(@project), notice: 'User story was successfully updated.' }
format.json { render :show, status: :ok, location: @user_story }
else
format.html { render :edit }
format.json { render json: @user_story.errors, status: :unprocessable_entity }
end
end
end
def edit
@project = Project.find(params[:project_id])
@user_story = @project.user_stories(params[:id])
end
def show
end
private
def set_project
@project = Project.find(params[:project_id])
end
def set_user_story
@user_story = @project.user_stories(params[:id])
end
def user_story_params
params[:user_story].permit(:param1, :param2, :param3, :row_order_position)
end
end
答案 0 :(得分:0)
只需要进行一些更改(实际上是调整),我会从上到下进行调整。
before_action :set_user_story
这将使用param[:id]
查找正确的@user_story
模型对象,并自动使其适用于正确的方法。在这种情况下,它except
为:create
,但也应该排除路线中没有:id
的其他方法。请改用:
before_action :set_user_story, except: [:index, :new, :create]
这将解决(或阻止)一些烦人且持久的ActiveRecord失败。
index
动作在此方法中,Rails命名约定的变量名称是非标准的。该变量当前是 singular ,但表示UserAction模型对象的列表,该对象通常使用plural
名称。请改用:
def index
@user_stories = @project.user_stories.rank(:row_order).all
end
此更改将导致app/views/user_stories/index.html.erb
视图中断,其中@user_story
变量的任何使用都需要更改为@user_stories
。遵守命名惯例有许多直接和长期的好处,因此值得付出额外的努力来改变它以保持一致。
注意:index
操作通常没有单数模型对象可供使用,因为此操作用于提供< em> list 模型对象。
new
动作 new
操作用于创建和初始化新模型对象以进行编辑。由于不再为before_action :set_user_story
操作调用new
,因此必须在此处创建@user_story
模型对象。此代码将正确执行此操作:
def new
@user_story = UserStory.new
@user_story.project = @project
# Set other important default values for display now
end
此时,您应该能够成功创建一个新的UserStory模型对象,准备好由用户进行编辑。
edit
动作由于已为[{1}}操作调用before_action :set_user_story
处理程序,因此无需在edit
的正文中查询@user_story
行动;该行可以删除:
edit
这实际上会修复报告的原始问题,因为def edit
@project = Project.find(params[:project_id])
end
的这种形式(不幸的是在这种情况下)将返回多个记录,这意味着您将收回一个集合,而不是单个记录。这是此错误消息的实际原因:
未定义的方法`to_key&#39; for #UserStory :: ActiveRecord_Associations_CollectionProxy:0x007f456a759138&gt;
在find
操作中分配@user_story
会覆盖先前从edit
处理程序分配的值,并将其替换为不正确的查询结果。
before_action
动作 complete
操作是自定义成员操作,这意味着它取决于complete
,就像许多其他操作一样。代码几乎是正确的,除了方法体内使用的:id
变量实际上缺少user_story
;这最初由@
处理程序检索。
before_action
可能在测试期间尚未调用此方法,因为def complete
@user_story.update_attribute(completed_at, Time.now)
redirect_to @project, notice: "User story completed functionality complete"
end
操作是失败的上游测试。当你开始测试这种方法时,这应该有效。
更改这些细节将最终确定UserStoriesController,它开始时状态非常好。添加这些更改,这是最终的控制器代码:
edit