What does (.:format) mean in rake routes' output? - ruby-on-rails-3

What does (.:format) mean in rake routes' output?
users GET /users(.:format) users#index

If you check the index action of your Users Controller then you will see something like this
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #users }
end
end
So, this format is the type of response which will be generated.
In routes, a placeholder for the type of response is created irrespective of whatever format has been defined in the action of the controller.
So, if your URL is something like :-
users GET /users --> users/index.html.erb will be rendered
users GET /users.json --> users/index.json.erb will be rendered
Similarly, if you want response in PDF or xls format, then you just have to define format.pdf or format.xls and also you have to define these new MIME types which are not there by default in rails in some initializer file.
So, then if a request is made like :-
users GET /users.xls --> users/index.xls.erb will be rendered
Your routes file will then just look for the format.xls in the index action and respective view file means users/index.xls.erb will be rendered.

Related

Rails goes to show action when I want custom action of open or expired

I am basically trying to do a custom index
In my routes.rb I have:
resources :tokens do
resources :visits
collection do
get :open
get :expired
end
end
My routes show as :
open_tokens GET /tokens/open(.:format) tokens#open
expired_tokens GET /tokens/expired(.:format) tokens#expired
I have open and expired defined in my tokens controller
def open
#q = Token.open_token.includes(:households, :visits).search(params[:q])
#tokens = #q.result
respond_to do |format|
format.html {render template: 'tokens/open'}
end
end
def expired
#q = Token.expired_token.includes(:households, :visits).search(params[:q])
#tokens = #q.result
respond_to do |format|
format.html {render template: 'tokens/expired'}
end
end
But it goes to my show controller with the following error:
Couldn't find Token with id=open
and it crashes at my Show action:
Better Errors shows the request as:
{"action"=>"show", "controller"=>"tokens", "id"=>"open"}
It seems to me that the action should be open with no parameters
What am I doing wrong?
I think I may have answered my question since it appears that Rails can only have one index per controller so I couldn't define another view that acts as an index.
So now what I want to do is pass a parameter so I can apply either an open scope or an expired scope

Test contents of file in rspec from respond_to format.csv

I have the following code in my controller that exports a csv file
...
def export
#filename = 'users.csv'
#output_encoding = 'UTF-8'
#users = User.active_users #not the actual scope but this only returns active
respond_to do |format|
format.csv
end
end
...
And I have the following in my spec
it "should only return active users"
get :export, :format => :csv
# i want to check that my mocked users_controller#export is only returning the active users and not the inactive ones
end
response.body is empty in this test when i check it. How would I go about getting the csv file in the spec that is downloaded when this action is hit in a browser so that i can check the result? I've hit a bit of a wall trying to figure this out.
Thanks for any help you can provide.
A test that checks that a CSV file is being created is as follows, assuming that the controller action is at 'csv_create_path'
it 'should create a CSV file ' do
get csv_create_path
response.header['Content-Type'].should include 'text/csv'
end
You sort of specify that CSV format is supported, but not what the contents should be. You could do
respond_to do |format|
format.csv do
render text: File.read(#filename)
end
end
to actually render that CSV file.
If you also have a normal HTML formatted view for the same data, you would simply have
respond_to do |format|
format.html
format.csv do
render text: File.read(#filename)
end
end
assuming you have setup appropriate instance variables for the HTML view before.

How to render JSON in Rails view

I've tryed the solution of following example: In Rails, how do you render JSON using a view?
But my problem is that the database already has a JSON string saved, I pull the json string and then I should be able to display the JSON file in the the view.
I'm using this because an android tablet should be able to visit the same url but depending on its settings (send by a POST) a different JSON file should be displayed, the android tablet then fetches the json and use it to configure some options.
So I already have a full working json file, i'm looking for a way to display it in a view (without rendering html tags and other stuff). I tryed the following (yes I've added respond_to :json) :
# def show_json (#config is the record, #config.json_config is the actual json configuration file
#config = event.et_relationships.where(terminal_id: terminal).first
respond_to do |format|
format.json
end
Then my view I have
#show_json.json.erb
<%= #config.config_json %>
Then the HTML I get to see (no errors are given)
<html><head><style type="text/css"></style></head><body></body></html>
Thanks!
EDIT
I'm using rails 3.2.3
Here is my routes (only relevant parts)
match '/events/config', to: "events#show_json", as: :show_json
resources :events do
member do
get :select_item
get :category
end
end
Then also the controller (partial)
respond_to :html, :json, :js
def show_json
#terminal_id = params["mac"]
terminal_id = "3D:3D:3D:3D:3D:3D"
event = current_user.events.where("date(endtime) > ? AND date(starttime) < ?", Time.now.to_s, Time.now.to_s).first
if event.nil?
# Nothing got returned so we use the default event
event = current_user.events.where('"default" = ?', true).first
end
logger.info "MAC: #{terminal_id}"
terminal = current_user.terminals.where(serial: terminal_id).first
logger.info "Terminal: #{terminal.attributes.inspect}"
logger.info "#{event.attributes.inspect}"
#config = event.et_relationships.where(terminal_id: terminal).first
logger.info "CONFIG #{#config[:config_json]}"
respond_to do |format|
format.json { render json: #config[:config_json] }
end
end
Use render:
#config = event.et_relationships.where(terminal_id: terminal).first
respond_to do |format|
format.json { render json: #config }
end
And then you have path /:model/:action.json.

respond_with/to rendering wrong view

I'm trying to understand why respond_with/to is rendering the wrong view...
controller
respond_to :html, :js
def get_numbers
Rails.logger.info request.format
#numbers = Number.all
respond_with #numbers
end
when making an ajax request, the rails log shows the format is JS, and the request format is text/javascript, but it renders the html view.
log
Started GET "/numbers/get_numbers?_=1333564838110" for 127.0.0.1 at 2012-04-04 11:40:38 -0700
Processing by NumbersController#get_numbers as JS
...
text/javascript
Rendered numbers/get_numbers.html.haml within layouts/application (106.4ms)
and i have both a get_numbers.html.haml & get_numbers.js.coffee view in views/numbers
i could render the correct view by doing:
respond_with #numbers do |format|
format.js {}
end
but shouldn't it be rendering the js view with just respond_with #numbers
If you want the response to be JavaScript when no format is explicitly specified (meaning no .html or .js in the URL), you can set the default format parameter in your route:
match '/numbers/get_numbers(.:format)' => 'numbers#get_numbers', :defaults => { :format => :js }
You might also get your desired results by switching the order of the formats in your call to respond_to, since it seems to default to the first one, but I haven't tested that.

how to display error information onto another page?

how to display error onto another page?
I have a form under user folder
And in another place, my_account folder, i render the form from user folder inside the index page of my_account. so that i can reuse the form,to allow user to update their user information.
So when user click update, update method in UserController will be invoked.
My question is, if faild to update user object, how can i display error message on to my_account index page, and still have the field highlight, and error message??
e.g invalid format of email address
User
-- new.html.erb
-- _form
my_account
-- index.html.erb
I tried to do following, but not sure how can i print the "error" in my_account page:
// try to update user information
// if failed, redirect to my account page
format.html { redirect_to my_account_path, :error => #user.errors }
I'm not sure about it but might work for you.
In update method of user_controller when you get any error just redirect to the index page of my_account and pass the error details with it to be displayed on index page. ie.:
def update
#user = User.find(params[:id])
## update process and if fails
redirect_to :action=> 'index', :status=>:unprocessable_entity, :error=>#user.errors
end
You need the errors to be set on the user object. This is used by form helper to display error messages when calling <%= f.error_messages %> inside your <% form_for %> block.
The Rails best-practice is to call render here, not redirect, so that we ensure we pass the #user object that has errors properly assigned.
To render the action, you can simply call:
if !#user.save
render :action => '../my_account/index'
end
This should easily solve your problem; just make sure to have all of your #member-variables set that the index.html.erb view expects.