Im writing an app that has a user model, and the users in this model can be two different user types.
user.rb
class User < ActiveRecord::Base
has_many :transactions
has_many :transaction_details, :through => :transactions
has_many :renters, :class_name => "Transactions"
end
transaction.rb
class Transaction < ActiveRecord::Base
has_many :transaction_details
belongs_to :user
belongs_to :renter, :class_name => "User"
end
transaction_detail.rb
class TransactionDetail < ActiveRecord::Base
belongs_to :transaction
belongs_to :inventory
scope :all_open, where("transaction_details.checked_in_at is null")
scope :all_closed, where("transaction_details.checked_in_at is not null")
end
Basically a user could be a renter, or the person checking the item out. Once I have a transaction, I can call:
#transaction.renter.first_name # receive the first name of the renter from the renter table
#transaction.user.first_name # receive the first name of user who performed the transaction
This is perfect and works as I explected. For the life of me, I can not figure out how to get the scope to work when called through a user:
# trying to perform the scrope "all_open", limted to the current user record, but I cant get it to use the
# renter_id column instead of the user_id column
u.transaction_details.all_open
is this possible to have a scrope look up by the second forien_key instead of user_id?
Short answer - Yes. This is very possible.
You need to mention the foriegn key being used in the reverse association definition.
In users.rb:
has_many :rents, :class_name => "Transactions", :foreign_key => "renter_id"
This will allow you to write:
User.find(5).rents # array of transactions where user was renter
If you want to call the transaction_details directly, then once again you would need to specify another association in user.rb:
has_many :rent_transaction_details, :through => :rents, :source => "TranactionDetail"
Which would allow you to call:
User.find(5).rent_transaction_details.all_open
Related
I want to create an app that uses both MongoDB and MySQL. Specifically, I want mongodb to store all the users' comments while MySQL will store the User model.
class User < ActiveRecord::Base
has_many :comments
end
class Comment
include Mongoid::Document
include Mongoid::Timestamps
belongs_to :user
end
well, everything looks good except when I go to the rails console and run this.
k = Comment.new
k.user = User.first
I got
NoMethodError: User Load (0.3ms) SELECT users.* FROM users
WHERE users._id = 1 Mysql2::Error: Unknown column 'users._id' in
'where clause': SELECT users.* FROM users WHERE users._id = 1
undefined method `from_map_or_db' for
It looks like that the := method is looking for the _id of the model instea of the id? Is there a workaround to get this working automatically or do I need to create my own = method?
Has anyone tried the same configuration before? If so, what are the steps to get all these to work?
This is not gonna work like you want it to. Your belongs_to :user in Comment is telling Mongoid to make this association in MongoDB; in order to make ActiveRecord associations, your class must inherit from ActiveRecord::Base or include ActiveRecord::Model--and you can't do both!
Probably the best way to do this--and I don't know how difficult it would be--is to write your own methods to associate the Users and Comments together.
You might try an association table:
class User < ActiveRecord::Base
has_many :thoughts, :foreign_key => "user_id", :dependent => :destroy
has_many :comments, :through => :thoughts, :source => :user
end
class Thought < ActiveRecord::Base
belongs_to :user, :class_name => "User"
belongs_to :comment, :class_name => "Comment"
end
class Comment
include Mongoid::Document
include Mongoid::Timestamps
has_many :thoughts, :foreign_key => "_id", :dependent => :destroy
has_one :user, :through => :thoughts, :source => :comment
end
I don't have any way of testing this at the moment but, it may work. Your thought model will need user_id and _id columns.
I have a User Model.
I have a Friend Model with columns invitee_id and Inviter_id and status. Status is used as flag whether friend request has been accepted or not. Inviter_id is the id of the user who sending the friend request and invitee_id is the user who is receiving the friend request.Please check inline comment.
class User < ActiveRecord::Base
has_many :friends // now i want to search all the friends with accepted friend request. (sent or received both.)
has_many :pending_friend_requests,:class_name => "Friend", :foreign_key=>"invitee_id", :conditions => {:status => 0}
end
class Friend < ActiveRecord::Base
end
Question is how to fetch all the friend with accepted friend requests.. sent or received as there are two foreign columns. invitee_id or Inviter_id
If I got your question right, this screencast is what you need.
Updated
Altough you say you don't, I think, you do need a self-referential many-to-many relation.
Instead of making an associations for pending requests, you could make a named scope. And after that, you could get all the friends you invited by User.find(params[:id]).friends.accepted.
What I can't understand is whether you want user.friends to retrieve both the ones who invited me and the ones invited by me OR only one of these.
Because of your namings (inviter and invitee) I suppose it is the second case. An it is covered in the screencast. It is done by creating additional inverted association (Ryan talks about that in the end).
But if it's the first one, the easiest solution would be to make two rows for each inviter-invitee pair. You could use this gem to simplify things, but it acts the same way I told.
If it doesn't help, try to specify your question.
The has_many sets up the relations. Use scope for conditions.
class User < ActiveRecord::Base
has_many :invitees, :through => :friends
has_many :friends, :foreign_key=>"inviter_id"
def accepted_invitees
invitees.where(:friends => {:accepted => true })
end
end
class Friend < ActiveRecord::Base
belongs_to :invitee, :class_name => "User"
belongs_to :inviter, :class_name => "User"
# needs accepted column
end
However, this is way to confusing because of the way that the models and columns are setup. If I were doing this I would do something like:
class User < ActiveRecord::Base
has_many :friends, :through => :friendships
has_many :friendships
def accepted_friends
friends.where(:friendships => {:accepted => true })
end
end
class Friendships < ActiveRecord::Base
belongs_to :user # change inviter_id to user_id
belongs_to :friend, :class_name => "User" # change invitee_id to friend_id
# needs accepted column
end
I am having a somewhat too nested database layout, however, I seem to need it. That is, Our website visitors may each have a single account with maintaining multiple users (think of identities) within.
Now they may create tickets, which are grouped by ticket sections, and we have ticket manager (operator) to process the incoming tickets.
Not every ticket manager may see every ticket but only those this manager is a member of the given ticket section for.
Now, I am totally fine in querying via raw SQL statements, but I failed to verbalizing those two special queries the Rails way.
Here is the (abstract) model:
# account system
class Account < ActiveRecord::Base
has_many :users
has_many :tickets, :through => :users
has_many :managing_ticket_sections, ... # TicketSection-collection this account (any of its users) is operate for
has_many :managing_tickets, ... # Ticket-collection this account (any of its users) may operate on
end
class User < ActiveRecord::Base
belongs_to :account
has_many :tickets
has_many :managing_ticket_sections, ... # TicketSection-collection this user is operate for
has_many :managing_tickets, ... # Ticket-collection this user may operate on
end
# ticket system
class Ticket < ActiveRecord::Base
belongs_to :author, :class_name => "User"
belongs_to :assignee, :class_name => "User"
belongs_to :section, :class_name => "TicketSection"
end
class TicketSection < ActiveRecord::Base
has_many :tickets
has_many :operators
end
class TicketSectionManager < ActiveRecord::Base
belongs_to :manager, :class_name => "User"
belongs_to :section
end
I am aware of basic has_many :through-constructs, however, here, I am accessing more than three tables to get the tickets.
Something that actually works for in the User's model is:
class User < ActiveRecord::Base
has_many :managing_relations, :class_name => "TicketSectionManager" # XXX some kind of helper, for the two below
has_many :managing_sections, :class_name => "TicketSection", :through => :managing_relations, :source => :section
has_many :managing_tickets, :class_name => "Ticket", :through => :managing_relations, :source => :section
end
Here I am using a helper relation (managing_relations), which is absolutely never used except by the two has_many relations below.
I were not able to describe a User.managing_sections nor User.managing_tickets relation without this helper, which is, where I need an advice for.
Secondly, the customer is to have a look at all of the tickets he can manage on any User (think of an identity) he has logged in, so what I need, is a way to collect all tickets (/sections) this Account is permitted to manage (identified by being a member of the corresponding TicketSection)
Here I even were not able to express this relation the ruby way, and I had to work around it by the following:
class Account
def managing_tickets
Ticket.find_by_sql("SELECT t.* FROM tickets AS t
INNER JOIN ticket_section_managers AS m ON m.section_id = t.section_id
INNER JOIN users AS u ON u.id = m.user_id
WHERE u.account_id = #{id}")
end
end
I'd appreciate any kind of advice, and
many thanks in advance,
Christian Parpart.
I'm working on a rails site that I've inherited and am trying to troubleshooting some sub-optimal model behavior. I have users, songs, and songs_download, each of which is its own model.
Here's the relevant line from the users model:
has_and_belongs_to_many :downloaded_songs, :class_name => 'Song', :join_table => :song_downloads
From the songs model:
has_and_belongs_to_many :downloaded_users, :class_name => 'User', :join_table => :song_downloads
And from the song_downloads model:
belongs_to :user
belongs_to :song
Here's the code to create a new song_download record when a user downloads a song (in the songs controller):
SongDownload.create( :song_id => #song.id,
:user_id => current_user.id,
:download_date => Date.today )
The problem I'm having is that once a user downloads a song, if I try to invoke the downloaded users from the interactive console, by, say, typing the following:
Song.find(<some id>).downloaded_users
I get back the complete record of the user, but the id in the returned objected is the primary key of the SongDownload, not the primary key of the User. All of the other fields are accurate, but the ID is not.
I didn't come up with this modeling scheme and it seems to me that :has_and_belongs_to_many might be more appropriately used with no explicitly modeled SongDownload object, but I'd rather not overhaul the codebase if I can help it. Are there any ways to get back the right user id given the current modeling scheme?
Thanks very much for your time and consideration!
Justin
Has and belongs to relationships are being phased out in favour of has many :through relationships.
On the upside you won't need to change any of your underlying structure, just the relationship declarations in the Song and User models.
class Song < ActiveRecord::Base
has_many :song_downloads
has_many :users, :through => :song_downloads
...
end
class User < ActiveRecord::Base
has_many :song_downloads
has_many :songs, :through => :song_downloads
...
end
Now
Song.find(<some id>).users
Returns an array of User objects which are joined to the selected song through the song_downloads table.
The has_many :through is recommended when the join table has more columns than simply two foreign keys.
class User < ActiveRecord::Base
has_many :song_downloads
has_many :downloaded_songs,
:through => :song_downloads,
:source => :song
end
class Song < ActiveRecord::Base
has_many :song_downloads
has_many :downloaded_users,
:through => :song_downloads,
:source => :user
end
Now you can get a list of users that have downloaded a particular song like so:
Song.find(1).downloaded_users
Right down to business....
There are tasks, which have assigned users
class Task < ActiveRecord::Base
has_many :task_assignments, :dependent => :destroy
has_many :assigned_users, :through => :task_assignments, :source => :user
validates_associated :task_assignments
end
And users have assigned tasks
class User < ActiveRecord::Base
has_many :task_assignments, :dependent => :destroy
has_many :assigned_tasks, :through => :task_assignments, :source => :task
end
The task_assignments table looks like this
class TaskAssignment < ActiveRecord::Base
validates_presence_of :user, :message => 'You must add some USERS fool!'
belongs_to :user
belongs_to :task
end
Those associations seem to be working well :0)
Here's the rub - when I add a new task through /tasks/new, I also want to specify a list of users assigned to that task, which the form is returning in "params[:users_list][:id]".
I can get this to work, but I don't want the form to validate unless there is at least one user selected.
I can't for the life of me figure out how to get this validation to take place in the models rather than in the create method.
As you can see, I've thrown "validates _associated :task _assignments" in the tasks method, but to no avail. I'm clearly in over my head.
Thanks for your help.
I think you have to name the parameter user_ids...
f.e.:
params[:users_ids][:id]