steven_noble
steven_noble

Reputation: 4203

How to use two controllers with one model in Rails

I have an Order model. Customers interact with the Order model through an Orders controller. Admins interact with the Order model through a Purchases controller.

Mostly it's working, except this happens:

  1. An admin user goes to new_purchase_path
  2. The app uses the "create" action in the purchases controller, as expected
  3. The app then uses the "new" action in the order controller (not the purchases controller)
  4. App then renders the "app/purchases/new" view (not the "app/orders/new" view), despite the fact that it has switched to using the orders controller
  5. After the admin creates the order, the app then renders the "app/orders/show" view using the orders controller

What I really need to happen is this:

  1. An admin users goes to new_purchase_path
  2. The app then uses the "create" action in the purchases controller
  3. The app then uses the "new" action in the purchases controller
  4. The app then renders the "app/purchases/new" view
  5. After the admin creates the order, the app then renders the "app/purchases/show" view using the purchases controller

In app/controllers/purchases_controller.rb I have this:

  def new
    @purchase = Order.new
    respond_with @purchase
  end

If have tried variations like...

  def new
    @purchase = Order.new
    respond_with @purchase, :controller => :purchases
  end

...but nothing like that is documented for respond_with, and naturally it doesn't work. What can I do?

Upvotes: 5

Views: 3248

Answers (2)

Chris Salzberg
Chris Salzberg

Reputation: 27374

The answer to this question is related to your last question. I've updated my answer there, but in a nutshell, the problem is not with respond_with (which as @jiri-pospisil points out you don't really need) but with your form generated by simple_form_for. The action url in that form defaults to /orders because @purchase is an instance of the class Order.

To fix that problem, specify the url in the form:

= simple_form_for @purchase, :as => :purchase, :url => purchases_path(@purchase) do |f|
  = f.error_notification
  = f.input :name
  = f.button :submit

You'll then find that you have another problem: after the new order (purchase) is created, respond_with will redirect to the show action of OrdersController. To fix that, you can use the location option:

def create
  @purchase = Order.new(params[:purchase])
  if @purchase.save
    respond_with(@purchase, :location => purchases_path(@purchase))
    ...

As you can probably tell at this point, using two controllers for a single model this way becomes somewhat convoluted, so you might want to consider namespaces instead.

Upvotes: 2

Jiří Pospíšil
Jiří Pospíšil

Reputation: 14402

A few observations:

  1. You should not use *respond_with* in the new action as it doesn't make sense for anything but HTML.
  2. You should use namespaces if you want to make some controllers for admins only. See http://guides.rubyonrails.org/routing.html#controller-namespaces-and-routing. That way you also don't need to change the name.

Upvotes: 3

Related Questions