Theoretical: method_missing - ruby-on-rails

I just started to learn Rails and I cannot understand that:
In my Post controller I do not have method show (not described), but I put in my controller that:
def method_missing(name, *args)
redirect_to posts_path
end
I think that if controller couldn't find action show - it would call method_missing and after that redirect to index method, but Rails tries to render view show.html.erb.
Why is method missing not catching? How can I use method_missing?

Rails does not require action to be present in controller if corresponding template exists. It just assumes empty action and renders template, that is why your method_missing isn't invoked.
If you don't need show action anyway - just remove show.html.erb and method_missing will work as expected.

Related

Rails controller methods

I have a controller action that is calling a model method to render some data. The controller looks something like this
class WeekController < ApplicationController
def index
#week = Week.first
end
def render
Week.render
redirect_to root_url
end
end
Currently my Week.render method has a bug in it and is causing errors. Which is fine, however when I am calling my index action the page fails because of the error in my render action.
Is it normal for rails to call actions other than the one being called or is there something weird going on?
It is ok to call other actions as long as you don't call redirect_to or render multiple times in a response.
By the way render is a reserved word, and you should not use it for a custom method.

Conditionally render a view if it exists? How to call render from a second method in a controller?

I am trying to render a custom partial if it exists, because I am running multiple websites with one codebase. The views are generally the same but sometimes they are different enough that it's easier to render a custom view.
Does anyone know how to call render from a method like below? The problem I am running into is that you have to call return after calling render, but I have to call return in the "index" method rather than calling the return in the "render_custom_view_if_exists" method. I can't seem to find a clever way to automatically check if the view exists and render it, since I would have to manually go into every method to call a return to cancel rendering the default view.
class ApplicationController
after_action :render_custom_view_if_exists
def render_custom_view_if_exists
render "#{path}" if lookup_context.template_exists?("#{path}")
return true
end
end
class UsersController < ApplicationController
def index
#users = User.all
end
end
ERROR: Render and/or redirect were called multiple times in this action.
Please note that you may only call render OR redirect, and at most once per action.
Also note that neither redirect nor render terminate execution of the action,
so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".
You could use append_view_path

Rails doesn't need index method in controller defined?

I noticed that an index view is routed correctly even if there isn't a controller method index.
As an example, the routes.rb has this route
AppName::Application.routes.draw do
get 'about' => "about#index"
end
My controller looks like this with no index method (def index end)
class AboutController < ApplicationController
end
and I have a view called index.html.erb in the views/about folder
What's happening here? Is this a case of rails magic where they automatically show the view even if there is no controller method? I couldn't find any documentation on this...
If you have the view file, it'll go ahead and render that implicitly, as documented here
See also, this SO thread on how Rails renders your view files and controller actions.

Trouble using a 'before_filter' method and rendering partials

I am using Ruby on Rails 3 and I am trying to understand the behavior of the before_filter method in a controller.
In my controller I have
class UsersController < ApplicationController
before_filter :authorize
def show
...
end
end
If I browse, for example, the page http://<my_web_site>/user/1 (that loads the users/show.html.erb view file populated of data from the User with ID 1) the before_filter works as well. That is, the authorize method does what it must do.
If I render the users/show.html.erb view file as a template for another controller (example: the PostsController) this way
# This code is in the `post/show.html.erb` file
<%= render :template => "/users/show", :locals => { :user => #user } %>
the before_filter doesn't work. That is, the authorize method seams do not run.
Why?! There is a reason for that behavior or I am wrong somewhere?
UPDATE (after the #brad comment)
Are you rendering that view as a
partial template from within the users
controller? If not the before_filter
won't apply
If it is as #brad say in his comment, how can I make the before_filter to work rendering that view for another controller than UsersController?
Move authorize method to ApplicationController
Add before_filter to each controller where you want to check user authorization.
When you render a template or a view file/partial, it is not really treated as a request on your controller, hence the filters dont apply.
Firstly you should understand the routing in the Rails. When you type in the browser http://<my_web_site>/user/1 then it goes to route file, after this to proper controller's action, after that controller initiate the render view. And controller has these callbacks, when some action is initiated then these callbacks should act before or after controller's action. So in your case you're calling partial template without any controller's involving
before_filter applies to controller actions, not rendering actions.
One solution, then, is to abstract your authorization logic out into a helper that can be used when you're rendering your partial:
if authorized?
render :partial => 'users/show'
end
Another solution is to implement authorization at the model level, using something like the declarative_authorization gem (https://github.com/stffn/declarative_authorization)

Render partial from a controller

I have a page composed by several partials (3).
One of them is a forum and when a user submit that forum, rails calls a create of a controller. After the object is created, I have to render the same page.
How is possible from the controller to recall directly the page with the partials already embedded ? Is it possible to specify manually the partial I want in the controller (I don't care if I violate the MVC paradigm).
Tnx
Try adding something like this to your application controller (this code is from authlogic gem):
def store_location
session[:return_to] = request.request_uri
end
def redirect_back_or_default(default)
redirect_to(session[:return_to] || default)
session[:return_to] = nil
end
Then, in the controller that renders the 3 partials, call store_location. Then, in the controller that creates the forum post, call redirect_back_or_default.
Hope this helps,
- Dave

Resources