How does ActiveRecord link records together? - ruby-on-rails

So this has been surprisingly difficult to locate a quick answer to. I'm using ActiveRecord in a pure console app, and I have my classes set up like so:
class Owner < ActiveRecord::Base
has_many :profiles
end
class Profile < ActiveRecord::Base
has_many :lines
belongs_to :owner
end
class Line < ActiveRecord::Base
belongs_to :profiles
end
Now normally i'd do something like..
Profile.create( :thing => "thing", :otherthing => "otherthing" )
How does AR know to link this instance of profile to an owner? What about a specific owner already in the database? How do I tell it? How would I do all of the links at once? (line, to profile, to owner)?

Read this to understand the basics. http://guides.rubyonrails.org/association_basics.html.

Related

Rails merging fields in two way has_many through relationship

I have the following models:
class User < ActiveRecord::Base
has_many :forum_users
has_many :forums through: :forum_users
end
class Forum < ActiveRecord::Base
has_many :forum_users
has_many :users through: :forum_users
end
class ForumUser < ActiveRecord::Base
belongs_to :forums
belongs_to :users
end
ForumUser has an additional "permissions" field to designate what the user can and cannot do within a particular forum.
The problem is that the "permissions" field on ForumUser is much more difficult to access than fields on Rails models normally are. In an ideal world, I would be able to make requests like:
user = forum.users.first
user.permissions
But once it's assigned, the User doesn't even remember the Forum it was attained through in the first place. It seems like there has to be a simple and straightforward Rails way of doing this. If so, what is it?

Validates association of an object

I have a weird case in my rails development that I'm not able to manage properly.
Basically, I have three objects: Domain, Project and Person ; a domain is a group of persons and projects. Domains can have several projects and projects can have several people however a project can only be in one domain and people can only work for projects in one domain.
I have represented it as following:
class Domain < ActiveRecord::Base
has_many :projects
class Project < ActiveRecord::Base
belongs_to :domain
has_and_belongs_to_many :persons
class Person < ActiveRecord::Base
belongs_to :domain
has_and_belongs_to_many :projects
I don't know how to validate that all the projects added to a person belongs to the same domain. I have created a method for validating persons however it is still possible to add projects in other domains, the person saved in database will just not be valid.
Do you see a clean solution to this problem?
So, basically, you want to validate that a person takes projects only from one domain. I suppose this domain should be defined, meaning a person should have a domain_id column.
You also have a many-to-many association, and, since the association needs some validations, you should have also a join model (instead of just a table without a model). I called it Work. So, I have this:
class Domain < ActiveRecord::Base
has_many :projects
end
class Project < ActiveRecord::Base
belongs_to :domain
has_many :works
has_many :persons, :through => :works
end
class Work < ActiveRecord::Base
belongs_to :project
belongs_to :person
end
class Person < ActiveRecord::Base
has_many :works
has_many :projects, :through => :works
end
Now, to the Work model you just add
validate :projects_belong_to_apropriate_domains
def projects_belong_to_apropriate_domains
if person.domain_id != project.domain.id
errors[:base] << "A person may only take a project which belongs to his domain."
end
end
This worked for me. Is this what you wanted?
You could setup a custom validation method for Person (taken from the rails guides)
validates :check_project_domain
def check_project_domain
projects.all.each do |p|
next if domains.exists?(p.domain.id)
errors.add :project_domain "#{p} is not a member of allowed domains"
end
end
I'm not to sure if you can call exists on a association, if not then you could replace it with something like:
domains.all.collect { |d| d.id }.include?(p.domain.id)
or even:
domains.where(:id => p.domain.id).count > 0

Exposing associations of a has_many -> has_many through the parent?

If a user has many things and a thing has many stats, it seems like there's only way Rails-y way to expose the stats through the user.
class User < ActiveRecord::Base
has_many :things do
def stats
Stat.where(thing_id: proxy_association.owner.things_id)
end
end
end
class Thing < ActiveRecord::Base
belongs_to :user
has_many :stats
end
class Stat < ActiveRecord::Base
belongs_to :thing
has_one :user, through: :thing
end
User.first.things.stats == Stat.where(thing_id: User.first.thing_ids)
I'm trying to determine whether there are any other options... Some people on my team complain that this doesn't feel natural. I feel like this is the most natural expression of the relationship you could devise.
Does anyone have a better suggestion? I'll say, I've tried instance methods and they don't smell right.
I might use a has_many :stats, :through => :things in the User class.
Check out this: http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association

Correct Associations Ruby on Rails

Can someone help me to correct my associations ?
I have the following models:
User, Developer, Application, Comments, Rating, Permission
Requirements:
A user can be a Developer or not.
A user can have Default Permissions and Permissions for each application
A user can install multiple Applications
A user can comment and rate multiple Applications
A developer can develop multiple applications
An application can request a list of permissions.
I already created some associations but I believe its not 100% correct or an easier way to do it exist.
Can someone suggest me a correct way to do it?
You are confusing models with authorization.
You should check out CanCan for role based authorization. For example you don't need your developer model since its just a user with a different role/permissions.
Edit: Changed 'role based authentication' to 'role based authorization'. As the comment below points out the difference between authentication and authorization.
I think this is what you want as far as your model work. You can use a join model to manage your application permissions, and use Rails STI to manage what each type of user can do, whether it's developing or not.
user.rb
class User < ActiveRecord::Base
has_many :apps
has_many :comments, :through => :user_comments
has_many :ratings, :through => :user_ratings
end
comment.rb
class Comment < ActiveRecord::Base
belongs_to :user
end
rating.rb
class Rating < ActiveRecord::Base
belongs_to :user
end
user_comment.rb
class UserComment < ActiveRecord::Base
belongs_to :app
end
user_rating.rb
class UserRating < ActiveRecord::Base
belongs_to :app
end
normal_user.rb (STI)
class NormalUser < User
end
developer.rb (STI)
class Developer < User
end
app.rb
class App < ActiveRecord::Base
has_many :permissions, :through => :app_permissions
has_many :user_comments
has_many :user_ratings
end
permission.rb
class Permission < ActiveRecord::Base
belongs_to :app
end
app_permission.rb
class AppPermission < ActiveRecord::Base
end
I agree with #Mark, don't use STI. The better way will be implement as suggested by #Chris Barretto except for STI and use CanCan for role based authentication. The change for User model will be:
class User < ActiveRecord::Base
has_many :apps
has_many :comments, :through => :user_comments
has_many :ratings, :through => :user_ratings
has_many :roles
end
And there will be another model for Role:
class Role < ActiveRecord::Base
has_many :users
end
If you are using gems like Devise for authentication, it will be much easy.

Cannot get data from related models in Rails

I have 2 models in different namespace.
class Admin::Membership < ActiveRecord::Base
has_many :authorization_roles
end
class AuthorizationRole < ActiveRecord::Base
belongs_to :membership
end
The Membership model is in different folder with AuthorizationRole model (I don't know what is called)
When run Admin::Membership.find(:all), the data from AuthorizationRole model is not included. I've create membership_id field on authorization_roles table, but I still can't get both models related. Is something wrong in this code? Sorry if I'm missing something basic here.
Try this
class Admin::Membership < ActiveRecord::Base
has_many :authorization_roles, :class_name => '::AuthorizationRole'
end
class AuthorizationRole < ActiveRecord::Base
belongs_to :membership, :class_name => 'Admin::Membership'
end
I've never used namespaced models and I don't think you need to... but maybe you'll have to specify the class name in AuthorizationRole, something like:
belongs_to :membership, :class_name => 'Admin::Membership'
UPDATE:
Assuming you have:
class Membership < ActiveRecord::Base
has_many :authorization_roles
end
class AuthorizationRole < ActiveRecord::Base
belongs_to :membership
end
You have added an integer column called membership_id to authorization_roles and you've run the migrations. Now you should be able to create authorization_roles like this #membership.authorization_roles.create( ... ) and fetch them #membership.authorization_roles
Check to see if you are setting the table name prefix. The Rails model generator adds a file like this for namespaced models:
# /app/models/admin.rb
module Admin
def self.table_name_prefix
'admin_'
end
end
Note: this is Rails version 3.0.1 -- not sure about earlier versions.

Resources