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
Related
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)
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.
In my application i need to set some deafult actions for all format.js and format.htm responses. At this moment I have something like this in all controllers:
def index
#users = User.all
respond_to do |format|
format.html {html_response}
format.js {js_response}
end
end
But I think that it isn't a good solution. What can I do?
Make a private method in your ApplicationController and call it from wherever required
class ApplicationController < ActionController::Base
…
private
def default_responses
respond_to do |format|
format.html {html_response}
format.js {js_response}
end
end
end
class SomethingsController < ApplicationController
def index
#somethings = Something.all
default_responses
end
end
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
:)
It's very simple, I want to handle a normal [show] request with a call to DataMapper like I did in Merb.
With ActiveRecord I could have done this:
class PostsController
def show
#post = Post.get(params[:id])
#comments = #post.comments unless #post.nil?
end
end
and it handles the 404 by catching the resource's exceptions.
DataMapper instead doesn't do this automatically so right now I'm solving it with this solution:
[moved in the answers]
It is possible to tell the controller to halt inside the not_found function?
I like to use exception throwing, and then use ActionController's rescue_from.
Example:
class ApplicationController < ActionController::Base
rescue_from DataMapper::ObjectNotFoundError, :with => :not_found
def not_found
render file => "public/404.html", status => 404, layout => false
end
end
class PostsController
def show
#post = Post.get!(params[:id]) # This will throw an DataMapper::ObjectNotFoundError if it can't be found
#comments = #post.comments
end
end
Done 'the old Merb way':
class ApplicationController
def not_found
render file: "public/404.html", status: 404, layout: false
end
end
class PostsController
def show
#post = Post.get(params[:id])
not_found; return false if #post.nil?
#comments = #post.comments
end
end
again: It is possible to tell the controller to halt inside the not_found function instead of explicitly calling 'return false' in the show action?
edit: thanx to Francois that found a better solution:
class PostsController
def show
#post = Post.get(params[:id])
return not_found if #post.nil?
#comments = #post.comments
end
end
As DM documentation says, you can use #get!