Difference between Active Model, Active Record and Active Resource - ruby-on-rails-3

Is there anyone who can help me by defining the exact difference between Active Model, Active Record and Active Resource. I have done enough googling in order to find the exact difference, but didn't get anything concrete which can tell the exact difference between them. Right now they all look same to me. So please give me the appropriate answer with some concrete points.

Rails 3 is designed with modularity in mind. Each module has its own purpose and functionality.
ActiveModel: This component was created in Rails 3. They took all the model related parts that did not have a database requirement of Rails 2 ActiveRecord and moved it into ActiveModel. So ActiveModel includes things like validations. More information: http://www.rubyinside.com/rails-3-0s-activemodel-how-to-give-ruby-classes-some-activerecord-magic-2937.html
ActiveRecord: This is the component that associates a class to the database. This will give the class functionality such as methods that make it easy to pull records from the database (An example is the find method).
ActiveResource: Similar to ActiveRecord. However, instead of being backed by a database, an ActiveResource object is backed by another application through a web service API. More information: http://ofps.oreilly.com/titles/9780596521424/activeresource_id59243.html
(Couldn't figure out about ActiveBase... where did you hear it from?)

What I understand:
ActiveModel + Database Support = ActiveRecord
ActiveModel via WebService API = ActiveResource

ActiveModel https://github.com/rails/rails/tree/master/activemodel
Think of a super model who is in constant need of validation.
ActiveModel can be used for many things, but mostly recognized for adding validation support to models / db records.
ActiveRecord https://github.com/rails/rails/tree/master/activerecord
Think record as in table record.
Sets up a mapping between a new class and an existing table in a database.
In the context of an app, these classes are commonly referred to as models. Models can also be connected to other models; this is done by defining associations.
class Firm < ActiveRecord::Base
has_many :clients
has_one :account
belongs_to :conglomerate
end
In the background, rails uses ActiveRecord for schema management and defining properties for your records, acting as an ORM (object relational mapper):
"ORM: An object that wraps a row in a database table or view, encapsulates
the database access, and adds domain logic on that data."
A schema outlines the properties for a record.
ActiveResource https://github.com/rails/activeresource
Think resource like the R in URL or of the resource routing that powers many rails backends.
Allows you to do things like Create, Retrieve, Update, or Destroy (CRUD) via HTTP.
tyler = Person.find(1)
When a request is made to a resource route, a RESTful request maps itself its corresponding HTTP verbs and their database interactions
GET => Person.find(1)
POST => Person.new(:name => 'Tyler', :favorite_page => 'stackoverflow')
PUT => tyler.save
DELETE => tyler.destroy

Related

How to implement HATEOAS in Rails

I've started with ActiveResource, but quickly hit the wall. Could not get ActiveResource to work when overriding to_json and to_xml on the underlying model. Plus, could not make resource representation inject links into the generated xml document. Oh btw, I'm using Rails 3.2.1.
I did a bit of research and found out about its gem. Tried it, for some reason didn't work for me. So my question is:
If I have one resource (say books) hosted in one web site (something like http://books.org), and another resource (say students, http://students.org), hosted in another web site, how can I get books to represent themselves to a student in their full HATEOS glory?
I was able to get the book resource to represent itself to the asking student as an XML document. I did that by using vanilla Rails ActiveResource in the students site. I've created Books resource that inherits from ActiveResource::Base. Then I specified the self.site and self.element_name, after which I was able to perform some rudimentary ActiveRecord-like queries against the remote books site. The only thing that worked for me was Book.all and Book.find(1). Even that was not satisfactory because the representation contained all database columns, and I wanted to at least remove some of those, which turned out not to be possible.
Now that I've abandoned that approach, I am wondering if there is a working example in Rails where it is possible to build a more sophisticated representation of a resource (i.e. books) that will contain links that will drive the application state transfer? I find it simply unbelievable that such a simple requirement seems so devilishly difficult to implement in Rails. All I'm trying to do is create a representation of a resource that will include some links which will guide the consumer on its discovery of what that resource is capable of. I'm mostly interested in implementing the workflow, which is a layered, peeling-the-onion type of conversational process of discovery.
In Rails, you'd need to change the way the serialization of your object happens if you're looking to do this in JSON. (You need to override the way Rails gives back representations of resources.) The most common gem for doing that would be: https://github.com/rails-api/active_model_serializers
If you don't want to use AMS or want to return HTML, consider following this presenter pattern: http://blog.steveklabnik.com/posts/2012-01-06-implementing-hateoas-with-presenters

Backbone.js on Rails - Access data in Rails outside of the Backbone model

I have a Backbone.js application with RoR for the backend.
The typical backbone.js setup is it gets the data from the table, and updates/saves data to that same table. However, my backbone model is made of a universal list of vendors, and I want a user to be able to "select" a vendor, which would dump into a DIFFERENT table, called user_selected_vendors.
I don't even know how to set this up in backbone. Any ideas?
Its hard to give specific advice without seeing some code examples.
In general though, you should think of your Rails backend as providing JSON service endpoints for your Backbone code to talk with. When your Rails app receives requests from the Backbone front end, you can do whatever is necessary with the request data. You are not limited to providing JSON endpoints which directly map to your database tables.
Also, based on the name of your user_selected_vendors table, it seems like you are not taking advantage of the ActiveRecord associations. What you may really want is something along the lines of adding has_many :vendors association to your User model. See: http://guides.rubyonrails.org/association_basics.html#the-has_many-association

How to create user specific content, that is invisible to others?

I am absolutely new to Ruby on Rails, even to programming at all. I got started with Michael Hartl's Rails Tutorial using Rails 3.0.10. Now I alter its aim towards creating an application that allows users to manage their own "projects". These projects are to be exclusively available to the logged-in user, thus, invisible to others.
My problem is: I am unable to create a page with an URL like "~/users/1/projects", I don't know about the routing. All i get done is "~/projects", which is fairly not what i want at all. So, how do I get this problem fixed? Or am I totally off track with that idea?
I generated a Projects model by scaffolding. So, how can I implement it for the signed-in users?
this would be done by creating a nested resource. when you are new to rails and programming you should work yourself a way through a lot of tutorials and guides.
a good place to get an overview are the official rails guides. in this specific case the chapter about routing: http://guides.rubyonrails.org/routing.html#nested-resources
# config/routes.rb
resources :users do
resources :projects
end

RoR - Foreign Keys created via associations and migrate or "by hand" (or scaffold)?

Just starting to learn Ruby on Rails. I'm using RoR 3. I have read this: http://guides.rubyonrails.org/association_basics.html
But I want to make sure I understand completely.
When creating a new model (I'm doing via scaffold for now), should I specify foreign_key fields at that point, or does the association handle that completely? I believe that association is only at app level, not at the db level, correct?
So I think I must do:
rails generate scaffold post body:text title:string user_id:integer
So in summary, when creating a blog application, must I specify the user_id field in the post model, or does the user model's has_many :posts take care of actually adding that to the db (mine is mysql) when I migrate?
And if the answer is that I should do them when I create the model in the first place (via scaffold or by hand), what happens when I decide later on that I want to add a foreign key, must I add that as an execute statement in a new migration?
You're correct. You need to specify the foreign key when you create your scaffold/model/migration as you stated to get the DB to be correct, and the has_many takes cares of the model for you.
So for initial generation of a scaffold (or model), just do:
rails generate scaffold post body:text title:string user_id:integer
as you stated, and add the has_many for the model itself.
For additions later on, you would make up a new migration, something like (assuming you want to use generation, but you could write your own migration):
rails generate migration add_user_id_to_posts user_id:integer
With that, you can run a rake db:migrate, and then update your model with a has_many or whatever association you need.

Rails 3 forms and models

I'm coming from Asp.Net MVC world and I'm confused how to approach Rails 3 forms from model perspective.
In Asp.Net MVC it is a bad practice to bind to business model forms in templates. The proper approach is to create a class for each form, create properties which are only needed in form and attach validation attributes to them. Then in code check for ModelState.IsValid and assign values from form model to business model. This leads to separation of concepts and also prevents properties hijacking (when hackers might post additional values together with proper values and change business model properties in his cruel way).
From all tutorials and books I've read there is no seperation of this concept in Rails world - you put validation in your business model and you bind your model to the form in the template.
Is it the right approach in Rails 3 and I should follow it? Or I should follow Asp .Net MVC approach and create a separate model with validation just for forms?
In rails, updates of models generally happen via mass-assignment. For example, a form posts a ton of attributes to your update action, your update action calls:
Model.update_attributes(params[:model])
and all the values in the passed hash are updated on the model. The problem then is what happens if a hacker adds
params[:model][:users_attributes][:email] = 'hacker#example.com'`
and updates the model's associated user's email address?
In Asp.Net MVC it seems like you simply don't allow this in the form template and the value can never get to your models, but in rails this is not the way things are done (correct me if I am misunderstanding Asp.Net MVC). In Rails, everything in a model (by default) can be mass-assigned, and so your fear is warranted.
In the link I supplied, you can see "For a normal user account, for example, you only want login and password to be editable by a user. It should not be possible to change the status attribute through mass assignment."
class User < ActiveRecord::Base
attr_accessible :login, :password
end
This means any other properties must be set manually and the object saved, thus preventing the same type of property-hijacking that Asp.Net's form templates protect against. In Rails, anything that should be mass-assignable should be in your attr_accessible and then ActiveRecord is the gatekeeper. No matter how your forms are written or what a hacker does to their HTML, those attributes can only be updated explicitly by your code, not by Rails' behind-the-scenes stuff.