ActionController::UnknownFormat when I use respond_to + respond_with (Rails 4) - ruby-on-rails

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

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)

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.

RoR: undefined method `http_basic_authenticate_with'

I'm following: The infamous RoR blog tutorial security section
And from some odd reason when trying to reach the specific relevant page i'm getting a:
undefined method 'http_basic_authenticate_with' for PostsController:Class error
I'm using:
Rails 3.0.9,
RubyGems 1.8.11,
Ruby 1.9.2p290
Any idea what might cause this or maybe a specific gem which is missing?
part of the controller code:
class PostsController < ApplicationController
http_basic_authenticate_with :name => "dhh", :password => "secret",
:except => :index
# GET /posts
# GET /posts.xml
def index
#posts = Post.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #posts }
format.json { render :json => #posts }
end
end
I think this method is only available to Rails 3.1 now, looking at the release notes:
http://guides.rubyonrails.org/3_1_release_notes.html#action-controller
Also the guide says:
This Guide is based on Rails 3.1. Some of the code shown here will not
work in earlier versions of Rails.
You can try this for rails version 3 and earlier:
class ApplicationController < ActionController::Base
USER, PASSWORD = 'dhh', 'secret'
before_filter :authentication_check, :except => :index
...
private
def authentication_check
authenticate_or_request_with_http_basic do |user, password|
user == USER && password == PASSWORD
end
end
end

How do I use respond_with with custom classes in Rails 3?

I am making a JSON API with Rails and it seemed to work fine except for when I use respond_with custom classes (not an ActiveRecord inherited one).
Here is my class:
class JsonResponse
def initialize(data, status)
#data = data
#status = status
end
def as_json(options={})
{
:data => #data,
:status => #status
}
end
end
which is a simple response wrapper. When I try doing this:
def create
unless(Match.find_by_user_id(params[:user_id]))
Match.create(:user_id => params[:user_id])
end
time_response = JsonResponse.new("5", "success")
respond_with(time_response)
end
I get this error:
NoMethodError (undefined method `model_name' for JsonResponse:Class):
app/controllers/matches_controller.rb:9:in `create'
Any ideas? respond_with is driving me crazy.
Your class should response to to_json method
Obviously set :location option in respond_with method. Rails try to create restful route from the object you pass to the method, but because your object is not resource, the error is raised.
I am not sure if this helps but I do not see respond_to...
respond_with works together with respond_to...
respond_to :html, :xml, :json
This can be defined on Controller level
example:
class UsersController < ApplicationController::Base
respond_to :html, :xml, :json
def index
respond_with(#users = User.all)
end
def create
#user = User.create(params[:user])
respond_with(#user, :location => users_url)
end
end
and then you can define your json template... don't know if you leave the json template empty if it takes your "JSONResponse" class...
just a thought...

How do I specify ":layout => false" in Rails' respond_with?

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
:)

Resources