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.
Related
My current Rails application has the following subdomains:
ui.myapp.com
api.myapp.com
I want to set up a staging environment, and I am wondering what is the best approach in order to set the domains.
Usually, I would do:
staging.myapp.com
But then, how do I access the UI/API sites?
Is it 'ok' to do:
ui.staging.myapp.com
api.staging.myapp.com
?
Assumption: The output from API call is expected in JSON format.
It will not be advisable to use separate subdomain for functionality like api.staging.myapp.com. You can always use the same url for web application and API
Better way would be to use same controller-action from Rails application but instead to return JSON output hash.
For example to get the users, you will have some code in users_controller.rb as
class UsersController < ApplicationController
def index
#users = User.all
respond_to do |format|
format.html do
render :index
end
format.json do
render :json => {:users => #users}
end
end
end
end
Now here if the request is html it will render the html page else it will return the json response.
staging.myapp.com/users will get you the html page of web application displaying users collection and that of staging.myapp.com/users.json will provide you the json response hash of users collection.
So, you will not need different subdomain to distinguish the api and normal site. But using format of request you can distinguish the functionality.
I hope this answers your question. If you still have any query feel free to ask.
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.
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
I want some users to be able to download data in a yaml file.
I see that you can do this with
send-file (but uses a lot of resources)
direct link_to the file in public folder (not good for me since the file is generated so the request needs to go to a controller.
restful url via controller (this method is partially explained in http://guides.rubyonrails.org/action_controller_overview.html but not enough to get it working!)
I followed this and tried something like
def show
#client = Client.find(params[:id])
respond_to do |format|
format.html
format.yml { render :yml => #client.redis_to_file }
end
end
redis_to_file returns a string with the yaml data
in config mime_types.rb
Mime::Type.register "x-yaml", :yml
then access like
clients/5.yml
All I get is "invalid template". (It's correct, I don't have a yml template in my views.)
Any clues about how to do this so that it works is greatly appreciated.
Try this:
respond_to do |format|
format.html
format.yml { send_data #client.redis_to_file, :type => 'x-yaml' }
end
There are more options in the Docs
I want people to be able to perform operations in ruby scripts using an API.
What options do you have in rails?
What if I want certain operations to be authenticated?
You can make any resource RESTful in rails by using resources in the routes.rb file. So if you have a table called items, then you could go resources :items. This will automagically make your controller accept any of the seven standard RESTful actions, new, create, index, etc.
Rails can deal with lots of different formats out of the box, html, json, xml, etc. So if you want someone to search your items, the code would look something like this when you go to a url that looks something like mydomain.com/items.json?search_term=HelloWorld:
class ItemsController < ApplicationController
def index
#item = Item.find_by_name(params[:search_term])
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #item}
format.json { render :json => #item } # this will get returned
end
end
end
If you want operations to be authenticated, then you could use something like the omniauth gem to do OAuth authentication via facebook, or something like that. You'll need some sort of library on your client side to manage the session as well, unless you recommend doing something icky like passing your user/pass in the URL.