首页 > 解决方案 > 嵌套资源,simple_form_for

问题描述

我正在尝试创建一个有活动的应用程序,每个活动都会有很多销售。创建新销售时,它会自动获取它所属的事件 ID。有人可以查看这个并告诉我我是否做错了什么,因为我认为为嵌套模型(Sale)创建 simple_form 的方式有点不正确。另外我不确定它是否应该这样或者我做错了什么,但是当我访问嵌套的孩子时,网址看起来像这样

.../events/4/sales/1 
.../events/3/sales/1 
.../events/5/sales/1 

但我希望它是这样的?!

.../events/4/sales/1 
.../events/4/sales/2 
.../events/4/sales/3 

这是我的事件控制器和模型

class Event < ApplicationRecord
  has_many :sales, dependent: :destroy
end

.

class EventsController < ApplicationController

  def index
    @events = Event.all
  end

  def new
    @event = Event.new
  end

  def create
    @event = Event.new(event_params)

    if @event.save
      redirect_to @event
    else
      redirect_to events_path
    end
  end

  def show
    @event = Event.find(params[:id])
    @sales = @event.sales
  end

  private

  def event_params
    params.require(:event).permit(:name, :comment, :event_disscount)
  end
end

. 这是我的销售控制器和模型

class Sale < ApplicationRecord
  belongs_to :event
  has_many :sale_items

  accepts_nested_attributes_for :sale_items, allow_destroy: true
end

.

class SalesController < ApplicationController
  def new
    @sale = Sale.new(event_id: params[:event_id])
    @event = Event.find_by(id: params[:event_id])
  end

  def create

    @event =  Event.find(params[:event_id])
    @sale = @event.sales.create(params[:sale].permit(:receipt_email))

    if @sale.save
      redirect_to @event
    else
      redirect_to new
    end
  end
end

路线.rb

Rails.application.routes.draw do
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
  resources :events do
    resources :sales
  end
  root 'events#index'

end

这就是我使用 simple_form 进行销售的方式(新)

<%= simple_form_for([@event, @sale])  do |f| %>

我主要关心的是销售控制器中的“新”操作,用其父级的 id 创建嵌套资源的最佳方法是什么,然后将此对象传递给 simple_form?!

先感谢您

标签: ruby-on-railsruby-on-rails-5

解决方案


你的问题太笼统了。基本上你做的很好,但是,通过对代码的一些改进,可以更容易地找到可能的问题。

我创建新销售的方式是否正确?

对您的一些改进SalesController

  1. 创建私有方法sale_params,它将清理表单中的输入参数。你已经为活动做过 - 为什么不在这里做呢?

  2. 由于该控制器在事件范围内工作,params[:event_id]因此为每个操作设置。所以创建一个before_action过滤器来设置你的@event变量。

  3. 方法create将模型保存到数据库中,因此save在它之后调用是没有意义的。

  4. 如果保存@sale到数据库失败,重定向到new是不合理的。在这种情况下,用户在表单中输入的所有内容都将丢失,不会显示验证错误,并且看起来像是您的应用程序的故障。使用new相同的@sale.

这就是我重写控制器的方式:

class SalesController < ApplicationController
  before_action: :set_event

  def new
    @sale = @event.sales.build
  end

  def create
    @sale = @event.sales.build(sale_params)

    if @sale.save
      redirect_to @event
    else
      render action: :new
    end
  end

  private

  def sale_params
    params.require(:sale).permit(:receipt_email, sale_items_attributes: [])
  end

  def set_event
    @event = Event.find(params[:event_id])
  end
end

推荐阅读