How do I do this query using metawhere and joins? - ruby-on-rails

I have User.rb:
has_many :sent_messages, :class_name => "Message", :foreign_key => "sent_messageable_id"
Each Message.rb has an account_id and a :givereceive method:
belongs_to :account
I want to create a method for the Account.rb model so that I can show all the Users (uniquetly) who sent a message where the account_id is the same as that account and :givereceive = "Give"
I tried the following:
User.joins(:sent_messages).where(
{:sent_messages => [:account_id => self.account_id,
:givereceive => "Give"]})
But I get an error that there is no association with Messages.
Also, this wouldn't remove duplicate instances (for example, the same user created several messages with the same Account).
I am testing it in the console and have the metawhere gem.
Thanks.

Try changing joins(:messages) to joins(:sent_messages)
User.joins(:sent_messages).where(
{:sent_messages => [:account_id => self.account_id,
:givereceive => "Give"]})

Add these associations to your models:
class Message < ActiveRecord::Base
belongs_to :account
belongs_to :user, :foreign_key => "sent_messageable_id"
end
class Account < ActiveRecord::Base
has_many :give_messages, :class_name => "Message", :conditions => {:givereceive => "Give"}
has_many :users, :through => :give_messages
end
Now to get the users you are looking for just call #account.users.

Related

Rails - how to make association between these models (not based on "id", but on "email")

I have these models that obviously have more attributes, but for simplicity I kept them just like this:
class User < ActiveRecord::Base
has_many :subs, :foreign_key => :email, :class_name => "subs"
end
class Subscription < ActiveRecord::Base
belongs_to :plan
belongs_to :user
end
In the table subscriptions, there's a column called email. This column points to the table users where matches an email address of a single user (the column email is in both tables unique).
I would need to create an association between these two models based on the email value. But when I try to run this query (and to get all subscription for the currently sign in user):
<%= current_user.subs.inspect %>
I get this error message:
uninitialized constant User::subs
I'd like to ask you guys for helping me with this association.
Thanks
uninitialized constant User::subs
This code
class User < ActiveRecord::Base
has_many :subs, :foreign_key => :email, :class_name => "subs"
end
should be like this
class User < ActiveRecord::Base
has_many :subs, :foreign_key => :email, :class_name => "Subscription"
end
When you are using a class_name option with the associations,it should point to the respected model classname(in your case it is Subscription not subs).Since there is no model with the classname subs,it throws that exception.
class User < ActiveRecord::Base
has_many :subs, :foreign_key => :email, :class_name => "Subscription", :primary_key => :email
end
class Subscription < ActiveRecord::Base
belongs_to :plan
belongs_to :user, :foreign_key => :email, :class_name => "Subscription", :primary_key => :email
end
You have to set the correct Class name and also you have to set the primary key.

Rails Unknown attribute error, but attribute does exist

I'm getting the error unknown attribute id when I run
#user.payments.create(payment_params)
I know this means I need a user_id in my payments table. But I'm using polymorphic associations (perhaps incorrectly?) and my payments table has a payee_id and a payer_id (for each "type" of user). In the above method the #user instance is a payer.
Here are the payment and user models:
class Payment < ActiveRecord::Base
belongs_to :payee, :class_name => 'User', :foreign_key => 'payee_id'
belongs_to :payer, :class_name => 'User', :foreign_key => 'payer_id'
end
class User < ActiveRecord::Base
has_many :payments
end
And the create action in the payment controller:
def create
#user = User.find_or_create_by(user_params)
#payment = #user.payments.create(payment_params)
end
The polymorphic associations are confusing me. How can I correct this error?
This is not a polymorphic association. You have to define relations correctly to get the payments you need to get. From the code i understand that this is kind of loan application.
The user in the above model does not have a single type of payment. There are two types of payments, the ones user gets money for, lets say incoming_payments and the one which user has to give money outgoing_payments. The relation should be defined like
class Payment < ActiveRecord::Base
belongs_to :payee, :class_name => 'User', :foreign_key => 'payee_id'
belongs_to :payer, :class_name => 'User', :foreign_key => 'payer_id'
end
class User < ActiveRecord::Base
has_many :incoming_payments, :class_name => 'Payment', :foreign_key => 'payee_id'
has_many :outgoing_payments, :class_name => 'Payment', :foreign_key => 'payer_id'
end
So if the user you are querying payments for is a payer then you should call user.outgoing_payements and if the user is a lender then you should call user.incoming_payments

Rails model joined has_many

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.

Relationship Type in Rails

Hi I am very new rails , would need some help , there is nothing similar I could find , i watch all the rail casts on the similar lines.
So I have a article model and user model ( devise ) .
I would to user to add article either in Follow Mode or Just Read Later Mode.
so UserArticleAssociation has article_id , user_id and association type . I am not understanding how to implement this feature correctly. I could make some hack to do these , but I don't want to.
Any tutorial on similar will be great help.
Try this:
class User < ActiveRecord::Base
has_many :user_articles
has_many :read_user_articles, :class_name => "UserArticle",
:conditions => {:mode => "read"}
has_many :follow_user_articles, :class_name => "UserArticle",
:conditions => {:mode => "follow"}
has_many :articles, :through => :user_articles
has_many :read_articles, :through => :read_user_articles, :source => :article
has_many :follow_articles,:through => :follow_user_articles,:source => :article
end
# Add a column called mode of type string (follow, read)
class UserArticle < ActiveRecord::Base
belongs_to :user
belongs_to :article
end
class Article < ActiveRecord::Base
has_many :user_articles
has_many :read_user_articles, :class_name => "UserArticle",
:conditions => {:mode => "read"}
has_many :follow_user_articles, :class_name => "UserArticle",
:conditions => {:mode => "follow"}
has_many :readers, :through => :read_user_articles, :source => :user
has_many :followers,:through => :follow_user_articles,:source => :user
end
Now you can do the following:
To add an article to read/follow category:
user.read_articles << article
user.follow_articles << article
OR
article.reader << user
article.follower << user
To access the articles
user.read_articles
user.follow_articles
To access the users
article.readers
article.followers
You should use has_many :through association. There is a Railscast about it here:
http://railscasts.com/episodes/47-two-many-to-many

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!

Resources