Rails model joined has_many - ruby-on-rails

Here is what I'm trying to do:
class Cashflow < ActiveRecord::Base
belongs_to from_account, :class_name => 'Account'
belongs_to to_account, :class_name => 'Account'
end
class Account < ActiveRecord::Base
has_many :cashflows
end
where Account::cashflows is obviously a list of all cashflows that either have the account_id stored in from_account or in to_account.
I'm confused. What is the proper way of handling such a case? How bad design is this? What would be the proper way of designing such a relation?

I think you have the right structure as there can only two accounts be involved in a particular transaction/cashflow. if you use many to many association you would need to handle the validation for not involving more or less than 2 accounts. For your current structure you can change your moidel associations to be:
class Cashflow < ActiveRecord::Base
belongs_to from_account, :class_name => 'Account', :foreign_key => :from_account
belongs_to to_account, :class_name => 'Account', :foreign_key => :to_account
end
class Account < ActiveRecord::Base
has_many :debits, :class_name => 'Cashflow', :foreign_key => :from_account
has_many :credits, :class_name => 'Cashflow', :foreign_key => :to_account
def cashflows
transactions = []
transactions << self.debits
transactions << self.credits
transactions.flatten!
## or may be the following commented way
# Cashflow.where('from_account = ? OR to_account = ?', self.id, self.id)
end
end
This way you can keep track of the amount debited/credited in a particular account and also get the accounts involved in a particular transaction/cashflow.

Suggestions on top of my mind
1) Your class (table) cashflows should have two columns from_account and to_account.
2) from_account and to_account should have the id of the account concerned
3) cashflows should belongs_to :account
4) account should has_many :cashflows. Ideally it should be cash_flows
These should be good starting points. Don't they meet your requirements?

I think you should use has and belongs to many association here:
class Account < ActiveRecord::Base
has_and_belongs_to_many :incoming_cashflows, :class_name => 'Cashflow', :join_table => :incoming_cashflows_accounts
has_and_belongs_to_many :outcoming_cashflows, :class_name => 'Cashflow', :join_table => :outcoming_cashflows_accounts
end
class Cashflow < ActiveRecord::Base
has_and_belongs_to_many :from_accounts, :class_name => 'Account', :join_table => :incoming_cashflows_accounts
has_and_belongs_to_many :to_accounts, :class_name => 'Account', :join_table => :outcoming_cashflows_accounts
end
Also you will need some validation code allows to add only one account to Cashflow.

Related

Association rules in rails

I have a User model, a Listing model and an Order model. A user can either place an order or publish a listing which others can place an order for. Thus, a User can be customer as well as supplier.
My Order model has listing_id, from_id and to_id.
My question is, how can I set up associations between these models ? I read the rails guide on associations but the example there were dealing with separate customer and supplier models.
class User < ActiveRecord::Base
has_many :listings, :foreign_key => :supplier_id, :inverse_of => :supplier
has_many :orders, :foreign_key => :customer_id, :inverse_of => :customer
end
class Listing < ActiveRecord::Base
belongs_to :supplier, :class_name => 'User'
belongs_to :order
end
class Order < ActiveRecord::Base
belongs_to :customer, :class_name => 'User'
has_many :listings
end

How to trigger multiple counter_cache in one model as has_many :through

I have 3 models(Allen, Bob, Chris) which are polymorphic with Join model. and a User model which connect with the join model.
class Allen < ActiveRecord::Base
has_many :joins, :as => :resource
...
end
class Bob < ActiveRecord::Base
has_many :joins, :as => :resource
...
end
class Chris < ActiveRecord::Base
has_many :joins, :as => :resource
...
end
class Join < ActiveRecord::Base
belongs_to :initiator, :class_name => "User", :foreign_key => "user_id"
:counter_cache => "How to write with 3 different counter cache?"
belongs_to :resource, :polymorphic => true, :counter_cache => :resources_count
end
class User < ActiveRecord::Base
has_many :joins
has_many :allens, :through => :joins, :source => :initiator
has_many :initial_joins, :class_name => "Join"
end
My question is how to write the counter cache for Bob, Chris and Allen in User Model
or you can review it here: https://gist.github.com/1350922
I think, there's no standard way to achieve this. Add an after_create callback to your Allen, Bob and Chris where you would get the list of all Users associated with this particular Bob and recalculate bobs_count for each of them manually.

Rails has many and belongs to one

I have a User model which has many projects and a Project model which can have many users, but also belongs to a single user (ie the user who created this project). It must belong to a User. It also allows a list of users to be associated with it, think collaboration.
With this in mind, my models look like this:
class User < ActiveRecord::Base
has_many :assigned_projects
has_many :projects, :through => :assigned_projects
end
class Project < ActiveRecord::Base
belongs_to :user
has_many :assigned_projects
has_many :users, :through => :assigned_projects
end
class AssignedProject < ActiveRecord::Base
belongs_to :user
belongs_to :project
end
Now, when I want to create a new project through a User, this is how I would do it:
user = User.create(:name => 'injekt')
user.projects.create(:name => 'project one')
Now, I know that projects is provided through an AssignedProject join model, which is why project.user will return nil. What I'm struggling to get my head around is the best way to assign the project creator (which by the way doesn't need to be user, it could be creator or something else descriptive, as long as it is of type User).
The idea then is to create a method to return projects_created from a User which will select only projects created by this user. Where user.projects will of course return ALL projects a user is associated with.
Assuming this kind of association is fairly common, what's the best way to achieve what I want? Any direction is greatly appreciated.
Add a creator_id column to your projects table for the creator relationship, and then add the associations to the models:
class User < ActiveRecord::Base
has_many :assigned_projects
has_many :projects, :through => :assigned_projects
has_many :created_projects, :class_name => "Project", :foreign_key => :creator_id
end
class Project < ActiveRecord::Base
belongs_to :user
has_many :assigned_projects
has_many :users, :through => :assigned_projects
belongs_to :creator, :class_name => "User", :foreign_key => :creator_id
end
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many
I wanted to add little improvement to design. We don't actually need intermediate model because it does not contain any extra column other than reference_ids hence HABTM association is best suited over here.
class User < ActiveRecord::Base
has_and_belongs_to_many :projects, :join_table => :assigned_projects
has_many :created_projects, :class_name => "Project", :foreign_key => :creator_id
end
class Project < ActiveRecord::Base
has_and_belongs_to_many :users, :join_table => :assigned_projects
belongs_to :creator, :class_name => "User", :foreign_key => :creator_id
end

Multiple References From Single Table

I've seen this issue referenced a few times, but nothing too complete. I'm having a problem with using a join table for a single model. For example, suppose we have Users and Highfives. Highfives will just be a join table for the two users highfiving. So I have this:
class Highfive < ActiveRecord::Base
belongs_to :user1,
:class_name => "User"
belongs_to :user2,
:class_name => "User"
end
class User < ActiveRecord::Base
has_many :highfives
end
However, with this, I am unable to do something like User.find(1).highfives since that generates a query like:
SELECT "highfives".* FROM "highfives" WHERE "highfives"."user_id" = 1
Really, I should be getting a query like:
SELECT "highfives".* FROM "highfives" WHERE "highfives"."user1_id" = 1 or "highfives"."user2_id" = 1
I imagine to do this I'll need to modify my User model in some way. But what am I missing?
Thanks.
You need to specify the foreign key in your has_many statement, otherwise Rails will assume it's user_id:
class User < ActiveRecord::Base
has_many :highfives, :foreign_key => :user1_id
end
Of course, this only works for a single foreign key. In your case, you'd probably want an instance method instead:
class User < ActiveRecord::Base
def highfives
Highfive.where("user1_id = ? or user2_id = ?", id, id)
end
end
Or, assuming it's impossible for a User to highfive himself:
class User < ActiveRecord::Base
has_many :highfives1, :class => "Highfive", :foreign_key => :user1_id
has_many :highfives2, :class => "Highfive", :foreign_key => :user2_id
def highfives
highfives1 + highfives2
end
end
Specify :foreign_key in your Models. So..
class Highfive < ActiveRecord::Base
belongs_to :user1,
:class_name => "User",
:foreign_key => "user1_id"
belongs_to :user2,
:class_name => "User",
:foreign_key => "user2_id"
end
class User < ActiveRecord::Base
has_many :highfive1,
:class_name => "Highfive",
:foreign_key => "highfive1_id"
has_many :highfive2,
:class_name => "Highfive",
:foreign_key => "highfive2_id"
end
Reference!

Going from 2 to many in Rails

I have a Rails application that I'm in the process of designing. I have a separate model that needs to link to only 2 of one model. Specifically, my "evaluation"s have 2 "member"s, an evaluator, and an evaluatee. They also have a few other pieces of information, too but they should not be relevant to this.
What is the best way to represent this? Would 2 foreign keys in the evaluation be best, or a many-many relationship between the evaluations and the members? Would there be some other option that would work even better?
I would initially think many to many, but since there is a defined number on one side of the relationship I question the applicability here. To my knowledge, many-to-many generally implies that the number on each side of the relation is variable.
You probably want two different associations, possibly with the same class:
class Member < ActiveRecord::Base
has_many :evaluations_out, :class_name => 'evaluation', :as => :evaluator
has_many :evaluations_in, :class_name => 'evaluation', :as => :evaluatee
end
class Evaluation < ActiveRecord::Base
belongs_to :evaluator, :class_name => 'member'
belongs_to :evaluatee, :class_name => 'member'
end
I haven't tested it myself and it might sound a little adventurous, but I think that could work:
Evaluation Model
class Evaluation < ActiveRecord::Base
belongs_to :evaluator, :class_name => "Member", :foreign_key => "evaluator_id"
belongs_to :evaluatee, :class_name => "Member", :foreign_key => "evaluatee_id"
end
Member Model
class Member < ActiveRecord::Base
has_many :evaluators, :class_name => "Evaluation", :foreign_key => "evaluator_id"
has_many :evaluatees, :class_name => "Evaluation", :foreign_key => "evaluatee_id"
end

Resources