How to prohibit any response except html in controller - ruby-on-rails

I have such code:
def show
#attachment = Attachment.find(params[:id])
respond_to do |format|
format.html
end
end
This code allows respond on json, but renders nothing. How to show custom page on any other request except html?

you can use format.any for any other request except html:
def show
#attachment = Attachment.find(params[:id])
respond_to do |format|
format.html { render text: => 'This is html' }
format.any { render :text => "Only html is supported" }
end
end

Try:
before_filter do
render text: 'Wrong type', status: 406 unless request.format == Mime::HTML
end

You can restrict the format of your routes when you define them in your config/routes.rb
scope :format => true, :constraints => {:format => :html} do
resources :attachments
end
Define all the routes whose format you want to restrict within that scope.

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)

Rails controller action without a view

I just want to do a rails action without a view.
In my 'routes.rb'
resources :pictures do
member do
post 'dislike'
end
end
In my 'PictureController.rb'
this does not work
def dislike
#picture = Picture.find(params[:id])
#like = Like.find(:user_id => current_user.id, :picture_id => params[:id])
#like.destroy
respond_to do |format|
format.html { render :action => :show, :id => params[:id], notice: 'You don\'t like this picture anymore.' }
format.json { render json: #picture }
end
end
neither do this
def dislike
#picture = Picture.find(params[:id])
#like = Like.find(:user_id => current_user.id, :picture_id => params[:id])
#like.destroy
respond_to do |format|
format.html { redirect_to #picture, notice: 'You don\'t like this picture anymore.' }
format.json { render json: #picture }
end
end
or even this (but this is not the case for me, i want a feedback to the user via json and via html)
def dislike
#picture = Picture.find(params[:id])
#like = Like.find(:user_id => current_user.id, :picture_id => params[:id])
#like.destroy
render :nothing => true
end
But i keep getting this error message:
ActionView::MissingTemplate: Missing template pictures/dislike, application/like with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :coffee]}.
How should i tell rails that this action in PicturesController does not needs a view?
Solved!
I didn't really solved the problem of telling rails i did not need a view, i just created another controller, put the method in it, and told rails routing to match the dislike action with a match call.
I cannot tell for sure, but i think it was a problem with the resources :picture in my routes.rb file...
But anyway, thank you guys!
=)
Something like this?
def dislike
#picture = Picture.find(params[:id]
#like = Like.find(:user_id => current_user.id, :picture_id => params[:id])
#like.destroy
render :nothing => true
end
Just created another controller with the dislike action:
def dislike
#picture = Picture.find(params[:id])
#like = Like.find(:user_id => current_user.id, :picture_id => params[:id])
#like.destroy
respond_to do |format|
format.html { redirect_to :back, notice: 'You don\'t like this picture anymore.' }
format.json { render json: #picture }
end
end
and modified my routes.rb to match this action:
match 'pictures/:id/dislike' => "likes#dislike", :via => :post
and my link to dislike now is
<%= link_to 'Dislike!', {:action => :dislike, :controller => :likes}, :method => :post %>
Most likely, the problem is that you're hitting this action via an ajax request. So the controller is looking for format.js, but you haven't specified a response for that format in your block. Thus it's falling through to the default.
Try
format.js { render json: #picture }
You may also need to tell the ajax request to expect a json response.

Rails method that handles ajax complaining about no template?

I have a subscriber#create method that is only used for ajax submits to it (the html form uses data-remote="true" to do the Ajax. The form does indeed submit and the data ends up in the db but the method throws an error saying that the template was not found.
How can I specify a function as being an Ajax handler in Rails? -- one that doesn't have to render a template, etc.
Here is what the method looks like:
class SubscribersController < ApplicationController
def create
Subscriber.create(:email => params[:email],
:ip_address => request.remote_ip,
:referring_page => request.referer ) unless Subscriber.find_by_email(params[:email])
end
end
You should handle the call in your respond_to properly.
...
respond_to do |format|
format.html
format.js { :nothing => true }
end
The thing it, you should probably return something. Even if it is an AJAX call, you should send something back to let the caller know that the creation was a success.
def create
#subscriber = Subscriber.new(#your params)
respond_to do |format|
if #subscriber.save
format.js { render :json => #subscriber, :status => :created, :location => #susbscriber }
else
format.js { render :json => #susbcriber.errors, :status => :unprocessable_entity }
end
end
end
Also, you shouldn't have to do the unless Subscriber.find_by_email(params[:email]) in your controller. You should just add validates_uniqueness_of :email to the Subscriber model.
you want something like render :layout => !request.xhr? in your controller, this will prevent the layout if the request is ajax

returning rails object by id & routing problem?(Ruby rails)

This should have been a relatively simple one but I must be making a mistake with my routes or something. I want to return an active record as json based on an id. So heres what I have and in my eyes it should have worked.
The route:
match '/repository/infoid/(.:id)(.:format)' =>'repo#infoID', :via =>:get
The def within the controller
def infoID
puts (params[:id])
#specificObject = myObject.find_by_id(params[:id])
respond_to do |format|
format.xml{
render :xml =>
{
:returnedObject => #specificObject
}
}
end
end
Why is it that when I go to my address of http://127.0.0.1:3008/repository/infoid/1.xml
I get no route found for /infoid/1.xml
get '/repository/infoid/:id' => 'repo#infoID'
little refacrtoring for controller
def infoID
#specificObject = MyObject.find(params[:id])
respond_to do |format|
format.html{}
format.xml{
render :xml => #specificObject
}
end
end

Routing to new action (Rails)

I have an action in my PostsController named 'tagged', which I want to return all posts tagged with whatever term.
In my routes.rb I have the following (at the top):
map.connect 'posts/tagged/:tag', { :controller => 'posts', :action => 'tagged', :tag => /[a-z\-]+/ }
Yet navigating to posts/tagged/yes returns a RecordNotFound error:
Couldn't find Post without an ID
In my tagged.html.erb file, I'll eventually be using the find_tagged_with method from acts_as_taggable_on_steroids, but for now I've put a simple Post.find(:all) to eliminate the possibility of error.
It seems like my map.connect is being overridden, and the same error occurs even if I comment the whole of the routes.rb file out except my new line.
Ok, because you can comment out the default routes that means your problem is not in your routes at all. It's that your tagged action in the posts controller probably has something like this.
def tagged
#post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #post }
end
end
Or perhaps if you spent a little more time it looks like this:
def tagged
#post = Post.find(params[:tagged])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #post }
end
end
Where as what you want is this:
def tagged
#post = Post.find(:all, :conditions => {:tagged => params[:tagged]})
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #post }
end
end
Anyway, you should be writing functional tests for this stuff and not testing in the browser.
Why not add a RESTful route for the "tagged" action?
map.resources :posts, :member => { :tagged => :put }

Resources