【问题标题】:Use the same form on the same page for new and edit actions (simple_form & Rails)在同一页面上使用相同的表单进行新操作和编辑操作(simple_form 和 Rails)
【发布时间】:2019-01-17 08:46:21
【问题描述】:

我正在学习 Rails,希望能够在同一页面上使用相同的表单来添加元素(此处为“剂量”)或通过预填充表单来编辑现有元素(页面刷新后,我不需要动态执行)。

这是页面截图(views/cocktails/show.html.erb)

创建一个新的“剂量”可以正常工作,但是在尝试编辑 Rails 时会引发 “DosesController#edit 缺少此请求格式和变体的模板” 错误。

当我试图真正理解路由逻辑时,我这样做只是为了学习,即使这可能是一种不好的做法,而且我只想使用 Rails 来实现。

视图/剂量/_form.html.erb:

我将逻辑放入部分表单中以决定是创建还是更新@dose:

<% if @dose.new_record? %>
  <%= simple_form_for [@cocktail, @dose] do |f| %>
    <%= f.input :description %>
    <%= f.association :ingredient %>
    <%= f.button :submit %>
  <% end %>
<% else %>
  <%= simple_form_for @dose, url: url_for("doses#update") do |f| %>
    <%= f.input :description %>
    <%= f.association :ingredient %>
    <%= f.button :submit %>
  <% end %>
<% end %>

views/cocktails/show.html.erb:

我在这里调用“新的或编辑的”路径助手,将鸡尾酒 ID 和剂量 ID 传递给它,因为剂量属于一种鸡尾酒。

  <% @cocktail.doses.each do |dose| %>
    <li>
    <h4><%= dose.description %> - <%= dose.ingredient.name %></h4>
    <%= link_to "<i class=\"fas fa-pencil-alt\"></i>".html_safe, new_or_edit_dose_path(@cocktail.id, dose.id) %>
    <%= link_to "<i class=\"far fa-trash-alt\"></i>".html_safe, dose_path(dose.id), method: :delete, data: {confirm: "Are you sure?"} %>
    </li>
  <% end %>
  </ul>
  <%= render "doses/form" %>
  <%= link_to "Back", cocktails_path %>
</div>

routes.rb

此路径助手绑定到 GET 路由,与剂量控制器的编辑操作相关联。因此,我根本不会使用 dose#new 路线操作。

  root to: "cocktails#index"
  resources :cocktails, only: [:index, :show, :new, :create] do
    resources :doses, only: [ :create]
  end
  resources :doses, only: [ :update, :destroy]
  get "cocktails/:id/doses/:dose_id", to: "doses#edit", as: :new_or_edit_dose

doses_controller.rb

  def edit
    @cocktail = Cocktail.find(params[:id])
    @dose = Dose.find(params[:dose_id])
  end

  def update
    if @dose.update(set_params)
      redirect_to cocktail_path(@dose.cocktail)
    else
      render(:edit)
    end
  end

  def set_params
    params.require(:dose).permit(:description, :ingredient_id)
  end

我对问题的理解

我想问题是我正在使用鸡尾酒/:id/doses/:id 路线,但在鸡尾酒/:id/show 视图上显示表单。我尝试在doses#edit 末尾使用redirect_to 并将其传递给params,但没有成功。

谁能告诉我这是否可行,并提示我应该寻找什么?

【问题讨论】:

  • 已找到编辑和更新路线,但如果视图目录中的 rails 找不到名为编辑或更新的模板,则会引发此错误。因此,如果您不想在一个模板中同时包含两个操作,则必须告诉 rails 在更新或编辑操作中要呈现什么。

标签: ruby-on-rails routes simple-form


【解决方案1】:

解决方案:

关于

...但是当尝试编辑 Rails 时会引发 DosesController#edit 缺少此请求格式和变体的模板

... 表示您缺少文件app/views/doses/edit.html.erb。所以只要创建那个文件,或者...因为你说...

我想问题是我正在使用鸡尾酒/:id/doses/:id 路线,但在鸡尾酒/:id/show 视图上显示表单

...如果理解正确,您希望此 url cocktails/:id/doses/:id 显示与您的 cocktails/:id/ 完全相同的页面(可能映射到您的 cocktails#show 页面,那么您可以执行以下操作:

app/controllers/doses_controller.rb:

# ...
def edit
  @cocktail = Cocktail.find(params[:id])
  @dose = Dose.find(params[:dose_id])

  render 'cocktails/show'

  # rails by default has an invisible line at the end of the actions, unless `render` is called manually like line above. But removing the line above, you'll get something like below
  # render 'CONTROLLER_NAME/ACTION_NAME.FORMAT.TEMPLATE_ENGINE'
  # so in this specific case:
  #   CONTROLLER_NAME == doses
  #   ACTION_NAME == edit
  #   FORMAT == html
  #   TEMPLATE_ENGINE == erb
  # which translates to:
  #   render 'doses/edit.html.erb'
  # which you can also do like the following
  #   render 'edit.html.erb' # because same controller name as the template being called
  # which you can also do like the following
  #   render 'edit' # because it automatically identifies what format using the value of `request.format`, and what default template engine your Rails app is configured to use
  # ... and this is the reason why you got that error "DosesController#edit is missing a template...", because app/views/doses/edit.html.erb does not exist, which by default is being rendered

建议:

  • 请先说明您为什么想要以下路线,我会看看我是否有更好的解决方案:

    get "cocktails/:id/doses/:dose_id", to: "doses#edit", as: :new_or_edit_dose
    

...我问这个是因为通常“创建或更新”/“新建或编辑”请求是针对某些唯一属性标识符进行路由的。例如,在您的情况下,唯一属性标识符似乎是:dose_id,因为如果:dose_id 尚不存在,您“创建”一个新的Dose 记录,或者如果您“更新”Dose 记录,如果它已经存在,其 id 值等于 :dose_id。现在,这是我的意见,但我认为从手动设置的“id”创建 Dose 记录不是一个好主意,因为您通常让数据库自动分配主键 id 值。

...为了解释我的观点,例如,模拟上面所说的路由,假设我在浏览器中打开这个URL:"/cocktails/1/doses/1",到目前为止假设Dose(id: 1)已经存在,那么我将只是在页面上查看更新Dose 的表格。但是,假设我打开了"/cocktails/1/doses/9999999999",假设打开了Dose(id: 9999999999) does not exist yet,那么我将看到一个创建Dose 的表单......此时这仍然有效。当您已删除 Dose 记录时,会出现此问题。所以假设Dose(id: 1)已经被删除,然后我尝试再次打开"/cocktails/1/doses/1",因为它已经被删除了,然后我会看到一个表单来创建Dose(这仍然可以),但是会出现问题因为您正在重用应该是“主键”并且应该唯一标识资源的 id 值,因为依赖于这个唯一 id 值的关联/模型可能会被搞砸:例如我有一个 @987654346属性{name: 'Porsche', category_id: 23} 的@ 记录属于一个Category(23) 记录,该记录具有属性{name: 'vehicle'},然后不知何故Category(23) 已被销毁,然后使用相同的ID 重新创建!但是这次创建的属性假设已变为{name: 'fruit'}。现在,我的保时捷车变成了水果!!

但是,我可以想到一些你故意这样做的原因(即,如果你想将 id 值视为 uuid,它可能永远不会以编程方式重用),但我的想法是为了以防万一您还没有意识到这些可能的后果。

【讨论】:

  • 非常感谢所有这些解释! render 'cocktails/show 行完成了这项工作。之后,我只是在我的#update 中添加了一个 Dose.find 方法。关于访问不存在 ID 的潜在问题,实际上,如果我尝试访问 /cocktails/1/doses/,代码会引发错误,因为此 url 是我的 dose#edit 方法,它会查找 dose_id在数据库中:@dose = Dose.find(params[:dose_id])
  • 哦,你说得对,我现在又看了一遍你的控制器代码。哈哈,我知道你如何命名你的路线'new_or_edit_dose'。可能,您想更改它的名称,因为该路线并没有真正进行新的或编辑,而只是在进行表演。此外,您的 doses#edit 也没有进行新的或编辑。嗯,因为你说它基本上是在做一个鸡尾酒#show,除了鸡尾酒/show.html.erb 两者都做一个“鸡尾酒秀”和一个“渲染_form”的组合。所以我猜我会将路线命名为show_and_edit_cocktail_dose,但不是“新”。不过只有我:)
猜你喜欢
  • 1970-01-01
  • 2013-05-21
  • 2015-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多