How to use Rails respond_with with a create action and javascript? - ruby-on-rails

I've been reading about respond_with. and used it before in a couple of tutorials but dont really think I understand it fully.
The functionality I am trying to implement right now is this: I have a list of items of class Article, and each of them has a link to the create Favorite action. When the user clicks on it it the favorite instance is created and the user is redirected to the home page. I want this to work with AJAX without a page refresh, and execute some JavaScript on the article item to let the user know it's been favourited successfully. I've used the :remote => true attribute in the relevant link, so the action is executing remotely without problem, but I am a bit stuck on how to execute the action's .js.erb file.
I've done the following in the controller:
class FavouritesController < ApplicationController
before_filter :authenticate
respond_to :html, :js
def create
#article = Article.find_by_id(params[:article_id])
current_user.Favourites.create(:article => #article)
redirect_to root_path
end
The problem is, I dont know what parameter should i pass to respond_with. I've tried replacing the redirect with both respond_with #article, and respond_with without parameters, and while both of them work (the create.js.erb is called), I dont understand why...
I dont want to 'respond_with' anything, but only that when the action is executed via javascript, the create.js.erb gets called. Can anyone explain a) why does respond_with work anyway whatever I pass to it, and b) what is the right way to do this?
BTW, I am using Rails 3.0
EDIT: I understand it better if I use respond_to like in the following code, but I would like to understand respond_with better.
respond_to do |format|
format.html { redirect_to root_path }
format.js
end

I ran across this question several times trying to solve a similar problem. It turns out my controller wasn't inferring the format as I assumed it would from the content type or the fact that it's an xhr request.
In any case, it worked when I switched from this:
contacts_path
To this:
contacts_path format: :json
I didn't care for that per se, so I changed my ajax call to include the dataType option like this (per jQuery ajax documentation):
$.ajax({url: contactUrl, type: 'POST', data: data, dataType: 'json' });

Hi Oalo go through the link below, it concisely explains the respond_with and respond_to. It lists all the options that you can pass to respond_with
http://ryandaigle.com/articles/2009/8/6/what-s-new-in-edge-rails-cleaner-restful-controllers-w-respond_with
Hope this answers your query

Related

ActionController::UnknownFormat in Controller ( #index)

I have a link_to calling my #index. In this method lies a respond_to for a format.js so I can initiate some Ajax. Things is, when I look at the console I get an error 500 because of a "ActionController::UnknownFormat"
I have tested out differents solutions from older posts, but I can't figure out what I'm missing.
controler :
def index
respond_to do |format|
format.js { render partial: 'private/messages/load_more_messages' }
end
end
view :
<%= link_to "Load messages", private_messages_path(:conversation_id => conversation.id), remote: true %>
Does anyone have any thoughts on this ? It's supposed to be a text book case, but I've been hitting my heads against a brick wall with this one.
If you are loading a HTML partial try it like this:
def index
render partial: 'private/messages/load_more_messages'
end
Although i would recommend making a specific endpoint for fetching partials that you pass a route to since this might be something you do frequently in a project.
Something like this
def render_partial(partial_route)
render partial: partial_route
end
Well, after going around testing a wide range of ideas, I came back to my original thought and it worked perfectly. I don't know what went wrong the first time but now it is perfect.

Rails: action and views

My question is : do we need a view file for each action in our controller?
(like if we defined a say_hello action in a controller, is it necessary to add say_hello.html.erb in his view directory?
I'll edit this to say it depends (with same content). If you plan on using that controller action as JS or JSON you don't need a view file. if you want one to share in multiple views, the file can contain a shared partial (which can be used in other views). This examples is shown by the generators scaffolding create examples like this. They are helpful if you are learning rails. Not great otherwise.
If you were to share a partial, you could have a partial named _form.html.erb and then inside your say_hello.html.erb file, it would just call:
<%= render 'form' %>
If you want to render JSON or JS files you can respond_to in your action:
respond_to do |format|
format.html # say_hello.html.erb
format.json { render json: #hello } #no file needed
format.js { render js: #hello }
#format.js   {} #do nothing... or use a little javascript in there...
# or have a file named say_hello.js.erb and use your #hello variable
end
Edit:
One last update. Your say_hello.js.erb file can do the anything on another view (if called remotely):
say_hello.js.erb
<% if #hello.attribute == "some value" %>
$('#div_in_another_view').show();
<% else %>
$('#div_in_somewhere_else').hide();
<% end %>
You can do jQuery and anything you want to the view calling it (as long as it's using AJAX).
End edit
Guides are great place to get started. Railscasts.com as well (even though Ryan isn't updating anymore).
Edit: A great example on the different options on the respond_to is on this rails guide regarding javascript
You can just pass javascript straight from that format.js call, or use a file if you need more complicated stuff. You don't need to do anything also. You could just have it return xml or nothing as well, depending on your use case.
No, it is not required. For example, you can render json or xml data from the controller without needed a view at all. This article explains it very well http://guides.rubyonrails.org/layouts_and_rendering.html
No you do not need a view for each action. BUT you do need a view for each action that will reach the end of the method.
If you return anywhere in the action then you are fine. A view is only required when an implicit render is called due to execution reaching the end of the action.
No, it's really up to you and it depends on what the action will actually do. Actions can render different types content types: text, json, html, xml... etc. Here's an example:
def show
render xml: #something
end
This action doesn't have a view, but it'll output an xml when called. It can also render different things based on the format of the call:
def show
respond_to do |format|
format.html do
redirect_to '/'
end
format.json do
render xml: #something
end
end
end
The action may also redirect (again, this one doesn't have a file):
def show
redirect_to '/'
end
At the end, it's really up to the programmer to handle how the action behaves, but if you leave it empty, it'll assume there's a file to render.

How do you respond using a one-line piece of javascript in a Ruby on Rails controller action?

I haven't been able to find any useful resources online on how to do this. Basically what I'm trying to do is run a simple jQuery $('#test-div').show(); when my def show_div controller action is complete.
I've tried the following and it doesn't work. It actually renders HTML which is confusing to me. when I explicitly state that the method respond with js.
users_controller.rb
def show_div
#user = User.first
respond_to do |format|
format.js {}
end
# also tried
# render :js => "$('#test-div').show();"
end
show_div.js.erb
$('#test-div').show();
render :text should do what you are asking for -- just return raw text (which in your case happens to be JavaScript code) without doing anything to it.

Adding POST Params to render json methods in Ruby on Rails

I have a method called is_following in the user.rb model, and it checks to see if one user is following another.
Users Controller
def show
#user = User.find(params[:id])
respond_to |format|
format.json { render json: #user, :methods => [:image_url, :is_following] }
end
User Model
def is_following params
return "yep" if params[:follower_id] == id
end
However, I don't know how to pass params into the :is_following method in the controller. Anyone have any luck or solution to this?
This may not be the answer you're looking for but it definitely a solution. I recommend you stop using render to generate your JSON.
Gems such as jbuilder or rabl make it easier and gives you more flexibility.
Ruby on Rails is a MVC framework. You should leave view generation at the view layer. Doing this will save you from much more pain you'll endure in the future.

How can I access data from a Ruby on Rails application externally?

I'm trying to work with the data in my Rails application from within a separate Ruby script.
I read this forum post in which some people suggest that the best way to work with your data is to encapsulate the database within one application, and then have this application provide an API for working with that data. Because it's apparently bad to integrate your database into several different applications.
Well, now I want to work with some data from my Rails app from another script, but on the same system. How can I achieve this?
I might want to work with the data from my Rails app remotely in the future, but also from a script. I'm assuming this might require JSON or SOAP, but I would like to know before I go researching it.
Have you take a look at ActiveResource? It's specifically designed to expose data from a Rails model to another Rails app over HTTP.
Since Ruby on Rails follows REST, your application is, by default, it's own API. For example, say you have the following controller:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
respond_to do |format|
format.html
format.xml { render :xml => #user}
format.js
end
end
def index
#users = User.all
respond_to do |format|
format.html
format.xml { render :xml => #users}
format.js
end
end
end
Now, when hitting that controller via the web browser, it will render your views as you would expect. For example:
GET /users/1 => /app/views/users/show.html.erb
GET /users => /app/views/users/index.html.erb
However, if you change your requests to be something like:
GET /users/1.xml
GET /users.xml
You'll be returned XML data instead of your HTML views. You can now access this data from any other application by using some sort of REST Client, or simply by calling cURL from any command line.
You can append any extension to the end of your URL, and it will find the appropriate respond_to section.
Accessing the data is simple too, just make a request to your application using something like HTTParty. Look at the examples, they're pretty good.

Resources