Rails 3 rendering template missing without file ending - ruby-on-rails

I have an action in my controller as below:
def show
#post = Post.find_by_setitle(params[:setitle])
if !#post
render 'error_pages/404'
return
end
respond_to do |format|
format.html
end
end
If the render error_pages/404 I get a template missing. Switching it to render error_pages/404.haml.html works fine.
Why is this?
N.B. There is no actual error_pages controller or model. Just a convenient place to keep them.
Edit: I'm using mongoid and hence don't have access to ActiveRecord. Controller base can't be looking for a particular ActiveRecord exception?

From the documentation
The render method can also use a view that’s entirely outside of your application (perhaps you’re sharing views between two Rails applications):
Rails determines that this is a file render because of the leading slash character. To be explicit, you can use the :file option (which was required on Rails 2.2 and earlier):
You need either to pass the :file option, or to start the location string with a slash. Alternatively, you could use the Rails functionality to rescue from errors, and recover from ActiveRecord::RecordNotFound with a 404. See this post for details.

You should probably use render :template => 'error_pages/404'.
I think Rails is looking for a partial called _404.
Try it out 1:
render 'error_pages/404' (and name the file _404.html.erb)
Try it out 2:
render :template => 'error_pages/404' (and name the file 404.html.erb i.e. no leading underscore)

Related

ruby code is showing as html in template

I have a rails app which uses angularjs. Here I'm trying to render a template from rails controller and pass a resource to the template. But the ruby code for displaying the variables are showing exactly as it is in the html.erb view.
def fail
#order = Order.find(1)
render 'payments/fail'
end
in view
<%= #order.as_json %>
My guess would be that the problem is in the name of your view file. I'd guess that you named it something like fail.html instead of fail.html.erb. Without the .erb suffix, Rails just interprets the file as html text and renders it without interpreting the ruby code.
However, changing the file name isn't quite the correct solution. Since you want to render json instead of HTML you don't need to create a view template, so you should just delete the template file altogether.
All Rails models have an .as_json method automatically, so you can simply modify your controller's fail method like so:
def fail
#order = Order.find(1)
render json: #order.as_json
end
Also if you want to do something fancy and modify the json that is returned, you can define your own as_json method inside the model.

locate file loaded on respond_with #jobs

On my project I have
respond_to :json
load_and_authorize_resource
def show
respond_with #job_pattern
end
as per tutorial here http://blog.plataformatec.com.br/2009/08/embracing-rest-with-mind-body-and-soul/
it works like this: when a request comes, for example with format xml, it will first search for a template at users/index.xml
so I checked for job_patterns/index.json but didnt find any file with this name
can anyone guide me where i can find the file or how the output is generated here if it is not with the file.
Because respond_to :json does not render a view, rather it calls render json: #job_pattern.
render json:#job_pattern calls #job_pattern.to_json and sets the JSON string as the response body. You can do the same with XML or YML.
This is an example of the rails convention over configuration philosophy - if there is a show.json.[erb|haml] it takes priority. Otherwise rails will look for an instance variable which corresponds with the name of the controller (#job or #jobs for index) and attempt to serialize it as JSON.
Further reading:
Justin Weiss: respond_to Without All the Pain
Rails Guides: Layouts and Rendering in Rails
In your case, your action is show so the template associated with is show.json in views/[namespace]/show.json.
You should create this template, or if this template is not found Rails will automatically invoke to_json on the object passed to respond_with.
Refer to documentation.
Recents version of Rails with generated scaffold use show.json.jbuilder as template file.
For more info about it:
jbuilder

Ruby on Rails basic tips

Im new at Ruby on Rails language and I really need that someone explain me some 'topics' if possible.
I've created an app and I Scaffolded it and it created in the controller lots of code but I have doubts.
One of them is:
This app is 'empty' so far. It only has a 'New Book' in the first page.
//books\index.html.erb
||| <%= link_to 'New Book', new_book_path %> |||
new_book_path redirects me to books_controller
def new
#book = Book.new
respond_to do |format| //-----> What means this 'format'?
format.html # new.html.erb // What really mean two options for 'format'?
format.json { render json: #book } // What means render json: #book
end
# new.html.erb -> has this code inside
New author
/*<%= render 'form' %>
<%= link_to 'Back', authors_path %>*/
Can someone explain me what's hapenning here?
I know that these are really silly questions but I'm not getting it.
Thanks in advance.
The best two ways to understand Rails in-depth are reading its code (https://github.com/rails/rails) and reading Documentation (http://api.rubyonrails.org and http://guides.rubyonrails.org).
So you'll find enough information to cover this topic here: http://api.rubyonrails.org/classes/ActionController/MimeResponds.html or here: http://guides.rubyonrails.org/action_controller_overview.html.
But if you want short answer... listen to the story :)
The entire respond_to do ... end block is responsible for defining rules on how your app should response on different 'formats'. Rails supports a lot of different formats, i.e :html, :json, :xml (you even can define your own formats). Beside mime types it has variants: :desktop, :tablet, :phone. Obviously that with mime types you describe how you want to answer on different types of request and with variants you specify different options for various user agents.
:format variable passed into block has type ActionController::MimeResponds::Collector. They didn't call it so for nothing. It collects all different response types you specify inside block and then using headers section from http request picks an appropriate variant from that options.
Hope it was useful. But again, better check Documentation.
Rails uses MVC pattern in as its foundation ([http://en.wikipedia.org/wiki/Model–view–controller]). So what we've seen before was a Controller. And you can treat new.html.erb as a View for :new action for that controller.
The file itself is an html file flavored with ERB (NOT the same as Epic Rap Battles of History, but [http://en.wikipedia.org/wiki/ERuby]) template engine. ERB is able to inject chunks of ruby code into your pages. <% %> enclosing tag is used just for evaluation and <%= %> for injection of the result of evaluation. So in your case with <%= render 'form' %> you inject result of #render method call into your html and with :link_to helper you create link.
IN CONCLUSION: I recommend you to start with https://www.railstutorial.org. That's an excellent tutorial for starters. You'll find answers for most of your questions and even develop your own little Twitter! (at least 2nd edition is about Twitter).
respond_to is a Rails controller method (explanation here: http://api.rubyonrails.org/classes/ActionController/MimeResponds.html#method-i-respond_to), which gets a block as argument. In short, block is a part of code ran within method it has been passed to.
For a block you declare variable called 'format'. Because this in just variable name so you may declare it i.e. 'f' or whatever you want.
Within the block of respond_to method, you may declare how your controller action responds for given MIME type. So, for HTML you may leave it empty, however if you want your controller to respond to JSON (MIME: application/json and you define it in the request header from the client side), then you have to tell your controller that's the response has to be in json format.

Is there a way to render a different template based on current user without using conditionals

I have two different layouts, one is completely custom and the other is bootstrap. For admins we want to render a bootstrap view and for non-admins we render it normally. For the most part this is pretty straight forward because admins and users don't share many views -- but there are some.
My original idea involved overriding render so that it would check if there's a bootstrap version of a file. So for example there would be _user.html.erb and _user.bootstrap.html.erb which would have bootstrap specific templating.
I'd like to not modify any controllers so ideally, something like render 'form' would behave smartly and check if there's an _form.bootstrap.html.erb, and if there isn't it would fallback to _form.html.erb
First attempt
My first attempt looked something like this
# I don't think this is the actual method signature of render
def render(options=nil, extra_options, &block)
# if it should render bootstrap and options is a string and there exists a bootstrap version
# set it up to render the bootstrap view
super(options, extra_options, &b)
end
Current attempt
I'm thinking about registering a template that basically checks if a file exists and then uses erb. I haven't made any progress towards this yet.
I figured it out. This is how I did it:
This is set in the application controller, with a before_filter :render_bootstrap
def render_bootstrap
return unless bootstrap?
new_action = "#{self.action_name}.bootstrap"
has_bs_view = template_exists?(new_action,params[:controller],false) || template_exists?(new_action,params[:controller], true)
if has_bs_view
self.action_name = new_action
end
end
I decided to extend this even further so that inside of a view like show.bootstrap.html.erb you can still use render "form" without doing render "form.bootstrap". This was done by overwriting the rails render helper.

How to use partial in views with different alias MIME?

Im using 2 different sets of views for 2 different user's roles.
Im using register_alias :
Mime::Type.register_alias "text/html", :basic
in the controller:
class SomeController < ApplicationController
def index
# …
respond_to do |format|
format.html # index.html.erb (advance)
format.basic # index.basic.erb
end
end
end
In some case I have to use the same code in both views, then I would use a Partial, but because of the MIME alias, I have to use 2 identical partials:
my_partial.html.erb and my_partial.basic.erb
I think there is a solution to DRY the code and use only a partial.
Do you have some solutions ?
thank you,
Alessandro
Old Answer:
I probably tried 50 different things until I figured out the right way of writing the partial once, but it was worth it because it's super simple:
Inside your index view, you normally do:
<%= render "my_partial" %>
This implicitly gets mapped to the partial corresponding to the Mime you requested, so it implies having two partial implementations. If you want a DRY partial, simply explicitly specify the format:
<%= render "my_partial.html" %>
As an added bonus of this observation, if your responds_to block of code is really just to switch based on the format and has no logic inside it, you can entirely remove that block of code and things still work implicitly.
Rails 3.2 update:
Rails has deprecated support for the above and support has been completely removed in the latest version of Rails. The following is the correct way as of Rails 3.2:
<%= render :partial => "my_partial", :formats => [:html] %>

Resources