Andrew
Andrew

Reputation: 2445

Calling methods that render views conditionally in a Rails Controller

I am writing a Ruby on Rails application with a controller called "pages_controller" that is responsible for displaying pages to users. There are 3 different types of pages that can be displayed, and different things have to happen on the back end in each case, so I decided to break the functionality out into 3 methods within the controller. When the user requests a page, the "show" method is called, which figures out whether the page: 1. Belongs to the user 2. Belongs to another user, and can be viewed by the user requesting it 3. Belongs to another user, and cannot be viewed by the user requesting it (unauthorized)

The appropriate method is then called from there to display the page. The code looks something like this:

def show
    if (something)
      showMine

    elsif (something else)
      showAnother
    else
      showUnauthorized
    end
end

def showUnauthorized

    respond_to do |format|
      format.html # showUnauthorized.html.erb
    end
end

def showMine

    respond_to do |format|
      format.html # showMine.html.erb
    end
end

def showAnother

    respond_to do |format|
      format.html # showAnother.html.erb
    end
end

I am getting a template missing error because rails wants to render a view when "show" is called, but I do not want any views to be rendered when "show" is called. I simply want "show" to call the correct method from there, and the corresponding view for that method (showMine, showAnother, or showUnauthorized) to be rendered. How can I do this? Or am I going about this the wrong way entirely?

Upvotes: 4

Views: 2447

Answers (2)

Steve Rowley
Steve Rowley

Reputation: 1578

I basically agree with Samy's comment, but here's some background:

The method that tells Rails what view to use is render. If there's no call to that method in your show method, Rails assumes you have a view called show.xxx.xxx, e.g. show.html.erb, that is supposed to be rendered. Note that it doesn't assume template will be prefixed with show because that's the name of the method. It assumes it will be show because that's the name of the action. The name of the action is passed to the controller as part of the request; it's not simply derived from the name of whatever method has a respond_to block in it.

All the respond_to blocks do is specify different view templates based on the MIME type of the request, but since you never call render, all of those extra methods are still trying to call the show view (show.html.erb in every case), because you never told Rails to render any other view, and the action name is show.

So, instead of the respond_to blocks, just call render [some_view] in each of your other methods.

This might not be the clearest answer, but I'd suggest also reading the following:

http://ryanbigg.com/2009/04/how-rails-works-2-mime-types-respond_to/

It describes what respond_to does, in particular how it keys off the action name to determine what view to render.

Upvotes: 2

gabrielhilal
gabrielhilal

Reputation: 10769

You need to declare these new actions that you have created in the routes file, as they don't belong to the RESTful routes.
I sugest to keep only the show action in your controller and create the IFs in the show view using the render method to include the partials(_showMine.html.erb, showAnother.html.erb, showUnauthorized)

example:

show view:

if (something)
  <%= render 'showMine' %>
elsif (something else)
  <%= render 'showAnother' %>
else
  <%= render 'showUnauthorized' %>
end

I hope it helps...

Upvotes: 3

Related Questions