I want to make an ajax search query by a client's name, so I'm using a like clause (see this question). I was thinking of using the index action to respond to json format from clients_controller but I'm already using it to repond to html format and at the same time paginates my listed rows with will_paginate and will_paginate-bootstrap.
What is the best way? making a new method to respond to json format or should I use the index one with format? and How to do that?
I'm new with ruby on rails
clients_controller.rb
def index
respond_to do |format|
format.html
{
#something like this I know that I would return me a syntax error
#client = Client.paginate(:page => params[:page])
}
format.json
{
#something like this I know that I would return me a syntax error
#client = Client.where("client_name LIKE ? ", "%#{params[:client_name]}%" )
}
end
end
def other_method
#client = Client.where("client_name LIKE ? ", "%#{params[:client_name]}%" )
respond_to do |format|
format.json {...}
end
end
In my opinion, you should keep only your index action and just accumulate the scopes on your #client variable.
Remember that your SQL query is only sent to the database when performing an Array method like each on your variable, not before.
So you can write something like:
def index
#client = Client.all
if params[:client_name].present?
#client = #client.where("client_name LIKE ? ", "%#{params[:client_name]}%")
else
#client = #client.paginate(page: params[:page])
end
respond_to do |format|
format.html
format.json
end
end
You should create a new action with some fruitful name like search or search_by_client_name . It will solve your issue also and you will stick with rails restful routing.
If you want index action to serve both request then you can do something like this:
def index
#client = Client.paginate(:page => params[:page])
respond_to do |format|
format.html
format.json do
client = Client.where("client_name LIKE ? ", "%#{params[:client_name]}%"
render json: { client: client }
end
end
end
Related
In my action I wish to only respond with processing if it was called from an AJAX request. How do I check?
I want to do something like this:
def action
#model = Model.find(params[:id])
respond_to do |format|
if (wasAJAXRequest()) #How do I do this?
format.html #action.html.erb
else
format.html {redirect_to root_url}
end
end
You can check for a header[X-Requested-With] to see if it is an AJAX request. Here is a good article on how to do it.
Here is an example:
if request.xhr?
# respond to Ajax request
else
# respond to normal request
end
If you're using :remote => true in your links or forms, you'd do:
respond_to do |format|
format.js { #Do some stuff }
You can also check before the respond_to block by calling request.xhr?.
Update:
As of Rails 6.1.0, xhr?() does actually (finally) return a boolean value.
https://github.com/rails/rails/commit/0196551e6039ca864d1eee1e01819fcae12c1dc9#diff-60b77e427ea7ba142faa477fac10b8d0134cede4e35a3b1953c425200fadf1acL267-L269
Original Answer:
The docs say that request.xhr?
Returns true if the “X-Requested-With” header contains “XMLHttpRequest”....
But BEWARE that
request.xhr?
returns numeric or nil values not BOOLEAN values as the docs say, in accordance with =~.
irb(main):004:0> /hay/ =~ 'haystack'
=> 0
irb(main):006:0> /stack/ =~ 'haystack'
=> 3
irb(main):005:0> /asfd/ =~ 'haystack'
=> nil
It's based on this:
# File actionpack/lib/action_dispatch/http/request.rb, line 220
def xml_http_request?
#env['HTTP_X_REQUESTED_WITH'] =~ /XMLHttpRequest/
end
so
env['HTTP_X_REQUESTED_WITH'] =~ /XMLHttpRequest/ => 0
The docs:
http://apidock.com/rails/v4.2.1/ActionDispatch/Request/xml_http_request%3F
I like using before_action filters. They are especially nice when you need the same filter/authorization for multiple actions.
class MyController < AuthController
before_action :require_xhr_request, only: [:action, :action_2]
def action
#model = Model.find(params[:id])
end
def action_2
# load resource(s)
end
private
def require_xhr_request
redirect_to(root_url) unless request.xhr?
end
end
request.xhr?
if this return 0 then it means its an ajax request, else it will return nil.
if you are using :remote => true in links,form, then your response would come in js form instead of HTML, JSON, etc.
def action
#model = Model.find(params[:id])
respond_to do |format|
format.js
if (wasAJAXRequest()) #How do I do this?
format.html #action.html.erb
else
format.html {redirect_to root_url}
end
end
end
you also need to create, action appropriate js file, in your case action name is action, so file name would be - action.js.erb. also shift our action code inside action.js.erb file
I have a controller action that responds to the same root in two formats - html and json. But the code that runs for the html response is completely different than the one for the json response..
Now I have something like
def index
result_html = ...
result_json = ...
respond_to |format|
format.html
format.json { result = result_json.limit(10) }
end
end
and I would like to have it like
def index.html
result_html ...
end
and
def index.json
result_json ...
end
What would be the best way to organize it?
May be something like this will work for you.
def index
respond_to |format|
format.html { index_html}
format.json { index_json }
end
end
def index_html
...
end
def index_json
...
end
You can test for the format with request.format.symbol then when :json call your json action or when :html call your html action.
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
def index
#workouts = Workout.all
#user_workouts = current_user.workouts.order("created_at DESC") unless current_user.blank?
if #client.present?
#user_workouts = #client.workouts.order("created_at DESC")
end
respond_to do |format|
format.html # index.html.erb
format.json { render json: #workouts }
end
end
The issue in question here is the instance variable #user_workouts - I am using a nested route to be able to do something like /clients/1/workouts instead of /workouts which will show the current users workouts which if that were nested would be /users/1/workouts.
Any idiomatic way to handle this or is it normal to just let the conditionals creep in?
You could create a class method on Workout accepting a User instance
def self.for_user(user)
where(user_id: user.id).order("created_at DESC")
end
and then simplify your action
def index
#workouts = Workouts.all
#user_workouts = Workout.for_user(#client || current_user)
respond_to ...
If #client exists it will be passed to for_user, otherwise current_user will.
You could DRY it up a little with:
user = #client || current_user
#user_workouts = user.workouts.order("created_at DESC")
Other than that, it looks pretty good as-is.
This is the code from internet and I am having trouble understanding what does respond_to, format.html and format.js do in the controller.
def create
#review = Review.create!(params[:review])
flash[:notice] = "Thank you for reviewing this product"
respond_to do |format|
format.html { redirect_to #review.product }
format.js
end
end
Thank you for your time.
Ramya
respond_to(*types, &block) public
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
If the client wants HTML, we just redirect them back to the person list. If they want Javascript (format.js), then it is an RJS request and we render the RJS template associated with this action. Lastly, if the client wants XML, we render the created person as XML, but with a twist: we also include the person’s company in the rendered XML, so you get something like this:
http://apidock.com/rails/ActionController/MimeResponds/InstanceMethods/respond_to