How do I specify ":layout => false" in Rails' respond_with? - ruby-on-rails

I have this setup:
class UsersController < InheritedResources::Base
respond_to :html, :js, :xml, :json
def index
#users = User.all
respond_with(#users)
end
end
Now I am trying to make it so, if params[:format] =~ /(js|json)/, render :layout => false, :text => #users.to_json. How do I do that with respond_with or respond_to and inherited_resources?

Something like:
def index
#users = User.all
respond_with #users do |format|
format.json { render :layout => false, :text => #users.to_json }
end
end

Assuming you need JSON for an Ajax request
class UsersController < InheritedResources::Base
respond_to :html, :js, :xml, :json
def index
#users = User.all
respond_with(#users, :layout => !request.xhr? )
end
end
This seems like the cleanest solution to me.

Or to prevent you having to hardcode responses for each format in each action.
If you have no layouts for any of the actions in this controller it would be nicer to do:
class UsersController < InheritedResources::Base
respond_to :html, :js, :xml, :json
layout false
def index
#users = User.all
respond_with(#users)
end
end

I love #anthony's solution, but didn't work for me... I had to do:
respond_with(#users) do |format|
format.html { render :layout => !request.xhr? }
end
ps: posting an "answer" instead of a comment because stackoverflow comment formatting and "return key == submit" is infuriating!

I just found this out:
Even if it's JSON, Rails is still looking for a layout. As such, the only layout that it finds, in our case, is application.html.
Solution: Make a JSON layout.
So for instance, if you put an empty application.json.erb with a single = yield inside, next to your HTML one, the HTML layout is bettered by the JSON one. You can even use this to surround your JSON with metadata or things like that.
<%# app/views/layouts/application.json.erb %>
<%= yield %>
No other parameters needed, it automagically works!
Tested in Rails 4 only

class UsersController < InheritedResources::Base
layout -> (controller) { controller.request.xhr? ? false : 'application' }
end

You need to set this on your show action.
def show
render :layout => !request.xhr?
end
:)

Related

Making a sitemap.xml with Ruby on Rails 4

I am trying to make a sitemap for my Ruby on Rails 4 application. I would use a gem like this dynamic_sitemaps but I can't use it with Heroku so I looked around and found this tutorial: http://meghagulati.com/2013/12/05/sitemap-xml-on-heroku-with-ruby-on-rails/ to make my own (with small changes)
But I am getting this error when I go to myapp.com/sitemap.xml, I hope someone can help me to find the error.
ActionController::UnknownFormat in SitemapsController#index
ActionController::UnknownFormat Extracted source (around line #7): respond_to do |format|
#app/controllers/sitemaps_controller.rb
class SitemapsController < ApplicationController
def index
#static_pages = [root_url]
#movies = Movie.all
respond_to do |format|
format.xml
end
#series = Series.all
respond_to do |format|
format.xml
end
end
end
#app/views/sitemaps/index.xml.builder
base_url = "http://#{request.host_with_port}"
xml.instruct! :xml, :version=>'1.0'
xml.tag! 'urlset', 'xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9' do
xml.url{
xml.loc("http://myapp.com")
xml.changefreq("weekly")
xml.priority(1.0)
}
xml.url{
xml.loc("http://myapp.com/movies")
xml.changefreq("daily")
xml.priority(0.9)
}
xml.url{
xml.loc("http://myapp.com/series")
xml.changefreq("daily")
xml.priority(0.9)
}
#movies.each do |movie|
xml.url {
xml.loc "#{movie_url(movie)}"
xml.lastmod movie.updated_at.strftime("%F")
xml.changefreq("weekly")
xml.priority(0.5)
}
end
#series.each do |series|
xml.url {
xml.loc "#{series_url(series)}"
xml.lastmod series.updated_at.strftime("%F")
xml.changefreq("weekly")
xml.priority(0.5)
}
end
end
#config/routes.rb
resources :sitemaps, :only => :index
get "sitemap.xml" => "sitemaps#index", format: :xml, as: :sitemap
First of all, you respond_to must only be called once, so you need to change your controller method, e.g.:
class SitemapsController < ApplicationController
def index
#static_pages = [root_url]
#movies = Movie.all
#series = Series.all
respond_to do |format|
format.xml
end
end
end
This change should render an XML file in your browser when you visit the following URL:
http://lvh.me:3000/sitemaps.xml
Furthermore, you need to change your routes specification and use a string for the format rather than a symbol, i.e. change :xml to "xml":
get "sitemap.xml" => "sitemaps#index", :format => "xml", :as => :sitemap
You should see the same XML file in your browser when visiting the following URL:
http://lvh.me:3000/sitemap.xml
(lvh.me resolves to localhost)

ActionController::UnknownFormat when I use respond_to + respond_with (Rails 4)

I can't understand what's happening, when I ask for index action I receive ActionController::UnknownFormat, even existing a index.js file inside views/products folder. Anyone can help me to figure out what I'm missing out? I'm using Rails 4 and Ruby 2.0.0-p247.
class ProductsController < ApplicationController
respond_to :js
def index
#products = Product.published.newest.page(params[:page])
respond_with #products
end
end
You should specify the format on the petition, i.e:
get :show, :user_id => user_id, :format => :json

How do I define default respond_to for index & show action in application controller?

I was wondering is there any way to define default respond_to for index & show actions in Application Controller with an ability to override in other controllers that need some customization.
I think it's going to be easier with an example.
I'm using InheritedResources, CanCan/Authlogic and WickedPDF gems to generate my pdf and authorize users. I was wondering if I can dry up my code.
Here is what I have
class ProductsController < InheritedResources::Base
load_and_authorize_resource
respond_to :html, :xml, :json, :pdf
def index
#products = Product.page(params[:page])
index! do |format|
format.pdf do
render :pdf => pdf_file_name,
:show_as_html => params[:debug].present?
end
end
end
def show
show! do |format|
format.pdf do
render :pdf => pdf_file_name,
:show_as_html => params[:debug].present?
end
end
end
end
class CustomersController < InheritedResources::Base
def index
index! do |format|
format.pdf do
render :pdf => pdf_file_name,
:show_as_html => params[:debug].present?
end
end
end
def show
show! do |format|
format.pdf do
render :pdf => pdf_file_name,
:show_as_html => params[:debug].present?
end
end
end
end
This works just fine. But it seems redundant that I need to define format.pdf in every controller that I'm want to generate pdf for. Is there any way to move this to application controller or specify somewhere using inherited resources, and then just override this on a per controller basis? Any ideas?
Thank you
Ok I came up with the following solution for anyone else interested.
I figured I can add a controller that will inherit from InheritedResources, which inherits from ApplicationController, and then have all my other controllers inherit from it ( except for a couple of special cases that will inherit directly from application controller ( like the HomeController, that doesn't have any actions other than index, and is not tied to any particular model) - this way I can define certain defaults - that I keep using in all my controllers such as respond_to, and still enjoy the benefits of InheritedResources gem.
class DefaultInheritedResourcesController < InheritedResources::Base
# For CanCan authorization - pretty much makes it application wide, without the need
# to define it in each controller. Can still override it in ability.rb by making
# a resource readable to all users with a session.
# if user
# can :read, [Product]
# end
# Also for controllers that need special treatment, you can just inherit from ApplicationController
# and override with skip_authorization_check - but for my app it's rare (only HomeController),
# most of controllers deal with some kind of resource - so this is a useful convention for 99% of use cases.
load_and_authorize_resource
respond_to :html, :json, :xml, :pdf
# format pdf needs to be redefined on those actions where index! or show! are called.
def index
super do |format|
format.pdf do
render :pdf => pdf_file_name,
:show_as_html => params[:debug].present?
end
end
end
def show
super do |format|
format.pdf do
render :pdf => pdf_file_name,
:show_as_html => params[:debug].present?
end
end
end
end
Then in my ProductController I can do this ( notice where my ProductController is inheriting from.
class ProductsController < DefaultInheritedResourcesController
def index
#products = Product.page(params[:page])
super
end
end
Hope this is going to help someone.

uninitialized constant Builder::XmlMarkup

I am attempting to display a comments feed for my application but I keep running into the same error. In my controller I have:
respond_to do |format|
format.rss { render :layout => false }
end
I then have a index.rss.builder w/ something very similar to http://techgossipz.blogspot.com/2010/03/gnerate-rss-for-your-site-in-rails.html
I am using Rails 3. Is there something that I am doing wrong?
I've done it like this:
class RssController < ApplicationController
respond_to :xml, :html, :rss
layout false
after_filter :set_header
def set_header
response.headers['Content-Type'] = 'application/xml; charset=utf-8'
end
def hu
#feeds=Feed.order("created_at DESC")
respond_with(#feeds)
end
def en
#feeds=Feed.order("created_at DESC")
respond_with(#feeds)
end
end
And you can call /en.rss

Turn off layout for one of action

My situation:
View action of ReportsController should render pure html, but not as a file (to view it in browser and save it after). So for rendering I use view template view.html.erb and i neet to turn off any layouts for this action. But in other actions of this controller layouts should stay untouched.
Works only turning off for whole controller like this:
ReportsController < ApplicationController
layout false
But that doing it wrong :( for all the actions
I tried to use something like this in action:
def view
#report = Report.new(params[:report])
unless #report.valid?
render :action => 'new' and return
else
render :layout => false
end
end
What should I do?
This should do it,
def view
...
render :layout => false
end
Link to Documentation
Try this:
ReportsController < ApplicationController
layout false
layout 'application', :except => :view
In the respond block, add layout: false.
For example:
respond_to do |format|
format.html { render :layout => false }
end
If you want to get a non-standard template, with no layout you can use:
def non_rest
render template: 'layouts/something_new', layout: false
end

Resources