In my post_index action, I generate different kinds of "#posts" like..
def index
case params[:listing_type]
when "all"
#posts = get_all_post_from_memcached
when "most_popular"
#posts = get_all_most_popular_from_memcached
respond_to do |format|
format.html
format.js #for ajax reqeusts
format.xml #for rss etc
end
end
end
##updated
def index
case params[:listing_type]
when "all"
#the key here is teh same key I used for memcached
if stale?(:etag => 'all_posts_key')
#posts = get_all_post_from_memcached
else
head :not_modified and return
end
when "most_popular"
if stale?(:etag => 'most_popular_key')
#posts = get_all_most_popular_from_memcached
else
head :notified and return
end
respond_to do |format|
format.html
format.js #for ajax reqeusts
format.xml #for rss etc
end
end
end
From what I understand fresh_when takes a etag, and it is to be used if there is no difference in different kinds of rendered (in my case the rendering is different based on html or ajax)
and
stale? also takes an etag and surrounds the respond_to block.
In this case the etag will be different based on the different listing types. But it seems there isn't much flexibility in the way fresh_when or stale? can be used here?
Thanks
update. I changed the original block a little and now get a double render error what am I doing wrong, should "head :notified and return" just return the header and not touch the respond_to block?
If you have special response processing like the one in show method, then use stale? helper. If you don’t have any special response processing like the one in edit method and using default-rendering mechanism (i.e., you’re not using respond_to or calling render yourself) then use fresh_when.
Related
I've run into a bizarre issue running Rails 4.2.7: When I look at the HTML index view for a particular model, everything seems fine. When I request the same data via JSON, I only get a subset of the attributes.
My index action is just:
def index
#coverages = Coverage.all
end
If I call it with
http://localhost:3000/coverages
everything is there. If I call it with
http://localhost:3000/coverages.json
I only get 7 of the attributes returned, in addition to the :id, :created_at, :updated_at, and a :url to the instance (e.g. http://localhost:3005/coverages/1.json).
Is the JSON method somehow truncating the attributes? I never recall running into this before.
POSTSCRIPT:
I modified the index action to:
def index
#coverages = Coverage.all
respond_to do |format|
format.html {render :index}
format.json {render json: #coverages}
end
end
and now I get all the attributes. Probably I was violating Rails best practices by not including the explicit format statements, but I am still curious about my original result.
I'm posting the solution I found (in the Postscript of the question) here in case it is useful. Still an open question as to why the original configuration didn't work.
Modifying the index action to:
def index
#coverages = Coverage.all
respond_to do |format|
format.html {render :index}
format.json {render json: #coverages}
end
end
solves the issue.
I'm trying to call a javascript function (actually coffeescript) from a controller in a Rails 3.2 app.
I'm getting a Render and/or redirect were called multiple times in this action error.
My code looks like this:
#Model.controller
def index
#models = Model.all
my_action if current_user.name == "Bob" #or some other general conditional
...and some stuff
respond_to do |format|
format.html
format.js #this is needed to handle ajaxified pagination
end
end
def my_action
respond_to do |format|
format.js { render :js => "my_function();" } #this is the second time format.js has been called in this controller!
end
end
#functions.js.coffee.erb
window.my_function = ->
i = xy
return something_amazing
What is the correct way to call a js function from the controller?
Man, you missed argument for block. Primary mistake.
def my_action
#respond_to do # This line should be
respond_to do |format|
format.js { render :js => "my_function();" }
end
end
And MrYoshiji's point is right. But your error was on server side, had not reached client side yet.
For the style, I think that's okay if the js code is one function call only. If more JS code, it's better to render js template
# controller
format.js
# app/views/my_controller/my_action.js.erb
my_function();
// and some more functions.
Update: How to fix double rendering problem
You must have your #index return if condition met, or the method will continue to execute and cause rendering twice or more. Fix it like this:
def index
#models = Model.all
if current_user.name == "Bob"
return my_action
else
# ...and some stuff
respond_to do |format|
format.html
format.js #this is needed to handle ajaxified pagination
end
end
#some instance variables
respond_to do |format|
format.html
format.xml {...}
format.json {...}
end
Does respond_to simply send all instance variables to the next webpage or it does something more?
I'm wondering how much data would be sent by respond_to. For example, if I have many instance variables #one #two #three etc. Are they all sent by respond_to? Any other data would be bundled and sent as well? ?
You instance variables will not be sent anywhere without your direction.
You probably have a .html.erb template that renders the instance variables when an HTML request is received (format.html).
For the xml and json responses, you need to tell Rails what to do. For instance, you could supply a template .xml.builder.
Rails can also render certain structures (arrays etc.) for you automatically, simply by calling render json: #one
Rails goes through the registered formats and tries to find a compatible format, otherwise, it will raise an error.
Example:
def index
#stories = Story.all
end
index action does not have a respond_to block. If a client asks to get the page in TEXT format, it will lead to the following exception:
ActionView::MissingTemplate (Missing template blogs/index ... with { ... :formats=>[:text], ...})
We can easily fix this by adding a respond_to block:
def index
#stories = Story.all
respond_to do |format|
format.html
format.js
end
end
After the change, the client will get 406 error when the format is not supported. Also, your index action will respond to two new formats: js and HTML.
This article explains all the ways you can use respond_to blocks.
This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
What is the best way to learn Ruby?
Explain Iterator Syntax on Ruby on Rails
I'm still learning ruby, ruby on rails and such. I'm getting better at understanding all the ruby and rails syntax but this one has me a little stumped.
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #contact_lists }
end
respond_to is a method that takes a proceedure, I think. The two formats look like they may be method calls too, but I don't know.
respond_to is a method which takes block. The block takes one argument, which here is called format.
Now you call two methods on format. html which you call without arguments. And xml which you call with a block.
This block takes no arguments and contains a call to the render method with a hash as an argument. The hash contains the key :xml and the value #contact_lists.
Yeap, you're right.
Ruby method calls are a bit puzzling at first, because you can ommit the parethesis, and they may receive code blocks.
So, this is the explaination:
respond_to do |format|
Invoke the method respond_to and pass it a block on what to do with the format it will receive.
format.html # index.html.erb
With that object called format invoke the method html
format.xml { render :xml => #contact_lists }
And the method xml which in turns receive another block ( do / en and { } , are different syntax to pass block. )
end
Finish the first block
See this other , other answers.
I think this post can help you.
Also, take a minute to read the respond_to documentation.
It is worth to know that this method has changed in Rails 3.
Without web-service support, an action
which collects the data for displaying
a list of people might look something
like this:
def index
#people = Person.find(:all)
end
Here’s the same action, with
web-service support baked in:
def index
#people = Person.find(:all)
respond_to do |format|
format.html
format.xml { render :xml => #people.to_xml }
end
end
What that says is, "if the client
wants HTML in response to this action,
just respond as we would have before,
but if the client wants XML, return
them the list of people in XML
format." (Rails determines the desired
response format from the HTTP Accept
header submitted by the client.)
Supposing you have an action that adds
a new person, optionally creating
their company (by name) if it does not
already exist, without web-services,
it might look like this:
def create
#company = Company.find_or_create_by_name(params[:company][:name])
#person = #company.people.create(params[:person])
redirect_to(person_list_url)
end
Here’s the same action, with
web-service support baked in:
def create
company = params[:person].delete(:company)
#company = Company.find_or_create_by_name(company[:name])
#person = #company.people.create(params[:person])
respond_to do |format|
format.html { redirect_to(person_list_url) }
format.js
format.xml { render :xml => #person.to_xml(:include => #company) }
end
end
I have a group of categories and I access these categorizes via javascript several times during the average course of use for my application via JSON.
So in my control currently I have a
#categories = Category.all
respond_to do |format|
format.html # index.html.erb
format.json
along with the appropriate index.json.erb file that formats what I need as far as JSON.
Now I want to add some memcached functionality to this so in the index.json.erb file I have added
<% cache "JSON_CATEGORIES_ALL" do -%> block around my output
My question is how do I get my controller to call this cache key when responding to a JSON request and act normally, pulling from the database, on other calls?
Thanks
You can check the format of the request:
#categories = Category.all unless request.format == "application/json" and fragment_exists?("JSON_CATEGORIES_ALL")
respond_to do |format|
format.html # #categories is available
format.json # no database call if your cache fragment already exists
end
I figured it out... for anyone who stumbles upon this here it is.
#categories = Category.all unless request.format == "application/json" and Rails.cache.exist?("views/JSON_CATEGORIES_ALL")
NOTICE: the addition of views/ to the cache key! seems rails prepends this to caches made on a view.
agregoire: Thanks for the
request.format == "application/json"