How to access information using Rails in Join Model - ruby-on-rails

I have two models:
USERS
has_many :celebrations
has_many :boards, :through => :celebrations
BOARDS
has_many :celebrations
has_many :users, :through => :celebrations
CELEBRATIONS
:belongs_to :user
:belongs_to :board
I understand that I create a third join table and model called "Celebrations" which does not require an ID.
create_table :, :id => false do |t|
t.column :board_id, :int, :null => false
t.column :user_id, :int, :null => false
t.column :role, :string, :null => false
t.column :token, :string
t.timestamps
end
end
How do I access the information?
user.celebrations.role
user.celeberations.token
user.boards
board.users
Thanks in advance. I understand its a real newbie question.

Yes, you can but if the join table has additional attributes then you should convert it to the full model. I mean to create a new Rails model with id, article_id, author_id and additional fields like role.
This is the Rails way of implementing such things. There is a small overhead of making the join table a little bit bigger. However with full join model it is possible to use standard Rails functions to create and update that model.
As far I remember has_many :through option was added to support better join models.

Related

How to write has_many_polymorphs in rails 3

How can I write the following code in rails 3 without using the has_many_polymorphs plugin?
has_many_polymorphs :listings, :from => [:my_properties, :friend_properties, :public_properties, :private_properties, :job_listings, :truck_listings, :open_listings, :sale_listings], :through => :group_listings
This video help me allot to make this #154 Polymorphic Association
in key on your Polymorphic table you need a ID of the record you want to link to and the name of the table you want to link to.
I usual do it like:
Migration
create_table "cards", force: true do |t|
t.string '....', default: ""
t.integer "accountable_id"
t.string "accountable_type", default: ""
end
Cards Model
belongs_to :accountable, :polymorphic => true
Others Model
has_many :cards, :as => :accountable
I hope that this helps

Trouble with self referential model in Rails

I have a model named User and I want to be able to self reference other users as a Contact. In more detail, I want a uni-directional relationship from users to other users, and I want to be able to reference an owned user of one user as a 'contact'. ALSO, i want to have information associated with the relationship, so I will be adding fields to the usercontact relation (I just edited this sentence in).
I attempted to do this while using the answer to this question as a guide.
Here is the User model:
user.rb
class User < ActiveRecord::Base
attr_accessible(:company, :email, :first_name, :last_name,
:phone_number, :position)
has_many(:user_contacts, :foreign_key => :user_id,
:dependent => :destroy)
has_many(:reverse_user_contacts, :class_name => :UserContact,
:foreign_key => :contact_id, :dependent => :destroy)
has_many :contacts, :through => :user_contacts, :source => :contact
end
I also created the model UserContact as a part of connecting contacts to users:
usercontact.rb
class UserContact < ActiveRecord::Base
belongs_to :user, :class_name => :User
belongs_to :contact, :class_name => :User
end
Here is the create_users.rb migration file i used:
create_users.rb
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :phone_number
t.string :email
t.string :company
t.string :position
t.timestamps
end
end
end
And here is the create_users_contacts.rb migration:
create_users_contacts.rb
class CreateUsersContacts < ActiveRecord::Migration
def up
create_table :users_contacts, :force => true do |t|
t.integer :user_id, :null => false
t.integer :contact_id, :null => false
t.boolean :update, :null => false, :default => false
end
# Ensure that each user can only have a unique contact once
add_index :users_contacts, [:user_id, :contact_id], :unique => true
end
def down
remove_index :users_contacts, :column => [:user_id, :contact_id]
drop_table :users_contacts
end
end
However, for reasons unknown to me, I believe something has gone awry in the linking since on my users index page, I have a column using <td><%= user.contacts.count %></td>, but I get this error from the line when I attempt to load the page:
uninitialized constant User::UserContact
I think the issue may be something to do with the fact that I want to name users associated with another user as contacts, because I cannot find other examples where that is done, and as far as I can tell I am doing everything properly otherwise (similarly to other examples).
The closest similar problem that I found was outlined and solved in this question. The issue was incorrect naming of his connecting model, however I double checked my naming and it does not have that asker's problem.
Any help is appreciated, let me know if any other files or information is necessary to diagnose why this is occurring.
EDIT
After changing usercontact.rb to user_contact.rb, I am now getting this error:
PG::Error: ERROR: relation "user_contacts" does not exist
LINE 1: SELECT COUNT(*) FROM "users" INNER JOIN "user_contacts" ON "...
^
: SELECT COUNT(*) FROM "users" INNER JOIN "user_contacts" ON "users"."id" = "user_contacts"."contact_id" WHERE "user_contacts"."user_id" = 1
EDIT TWO
The issue was that my linking table, users_contacts, was misnamed, and should have been user_contacts! so I fixed it, and now it appears to work!!
You need to rename your usercontact.rb to user_contact.rb
This is naming convention rails autoload works with.

Inbox messages in rails like facebook

I am trying to create a personal inbox message system but couple question are on my mind. First let me explain my system.
Here is my table model
create_table "inboxmessages", :force => true do |t|
t.integer "receiver_id"
t.integer "sender_id"
t.integer "message_id"
t.boolean "isread"
t.boolean "isstarred"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "messages", :force => true do |t|
t.string "subject"
t.text "body"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
The relationship would be has follow
inboxmessages
belongs_to :message
belongs_to :user, :class_name => "User", :foreign_key => "sender_id"
belongs_to :user, :class_name => "User", :foreign_key => "receiver_id"
messages
has_many :inboxmessages
user
has_many :inboxmessages
The problem that i am having his i am uncertain on how to create a message which allows me multiple users. here the schema of the form i am trying to have
Message.subject
Inboxmessage.receiver # but have multiple different user
------------------------------------------------------------------------
Message.body
Inboxmessage.sender = current_user # hidden field
Here are the question that I have regarding building this model/controller/app
1 - Should my new form be in inboxmessages or messages?
2 - Should I use accept_nested_for or should I use nested resources
3 - Is my model/database is okay or not the best?
4 - Are my foreign_key relationship well define?
Thanks in advance!!
I would do something like this:
class User
has_many :mailboxes
has_many :messages, :through => :tags
has_many :tags
end
class Message
has_many :users, :through => :tags
has_many :mailboxes, :through => :tags
has_many :tags
end
class Mailbox
has_many :tags
has_many :messages, :through => :tags
has_many :users, :through => tags
end
class Tag
belongs_to :user
belongs_to :message
belongs_to :mailbox
# this class has "read?", "starred", etc.
end
This enables a message to appear in multiple mailboxes, for multiple users, and each user can have his/her own "read?", "starred", etc. You can limit the logic if you want to ensure that a user has only one copy of a message, i.e. the message is not in two or more mailboxes for the same user.
To improve your schema, read the Rails Guides, especially about associations like these:
belongs_to
has_one
has_many
has_many :through
inverse_of
Also look at the Rails gem acts-as-taggable-on
http://rubygems.org/gems/acts-as-taggable-on
One way to think of a message schema is "a message belongs to a mailbox, and a mailbox has many messages" (this is how Yahoo does it). Another way to think of a message is "a message has many tags, and a mailbox is simply a search by tag" (this is how Gmail does it).
By the way, the Ruby mail gem is excellent. You can use it for creating messages, and look at how it converts headers like from, to, cc, etc.
You asked good questions:
1 - Should my new form be in inboxmessages or messages?
My opinion is that you will get the most benefit if you have a model for the message that is like an email, have a model for a mailbox (or tag). To create a new message, the new form would typically be in ./messages/new.html.erb
2 - Should I use accept_nested_for or should I use nested resources?
Nested resources are fine; see the Rails guide here:
http://guides.rubyonrails.org/routing.html#nested-resources
Nested attributes are also fine; see the API here:
A good rule of thumb is to only nest one level down, because after that it gets more complicated than its worth.
3 - Is my model/database is okay or not the best?
Not the best. A real-world message will typically have a sender and receiver(s). But you're modeling the sender and receiver in the inboxmessages table. Better to model the message with has_many receivers, and use a separate model for the user's interaction with the message for example a table called "marks" with fields "starred", "isread", etc. A mark belongs to a message and belongs to a user. A message has_many marks, and a user has_many marks.
4 - Are my foreign_key relationship well define?
In general, yes. Just be aware that email is surprisingly hard to model. A good rule of thumb is to index your foreign keys. Also look at Rails associations "inverse_of" and use it; this will help with speed and memory use.
I would have my classes set up something like this.
class Inbox
has_many :messages
belongs_to :user
end
class User
has_many :messages
has_one :inbox
end
class Message
belongs_to :user
belongs_to :inbox
has_many recipients, class_name: "User", foreign_key: "recipient_id"
end

Making ActiveRecord join model attributes available in query results

Given User and Book models, I've created a join model, ViewedBook, that contains additional attributes. Below is the essence of what I've come up with:
create_table "users"
t.string "username"
end
create_table "books"
t.string "title"
t.integer "user_id"
t.date "authored_date"
end
create_table "books_viewings"
t.integer "book_id"
t.integer "user_id"
t.boolean "finished"
t.date "last_viewed_date"
end
class User
belongs_to :book_viewing
has_many :authored_books,
:class_name => "Book",
:source => :book
has_many :book_viewings
has_many :viewed_books :through => :book_viewings
:order => "book_viewings.last_viewed_date DESC"
has_many :finished_books :through => :book_viewings
:conditions => "book_viewings.finished = TRUE",
:order => "book_viewings.last_viewed_date DESC"
end
class Book
belongs_to :user
has_one :author, :class_name => "User"
end
class BookViewing
belongs_to :book
belongs_to :user
end
I think this works for most of the queries I need to create. However, I want each of the Book objects returned by user.viewed_books to include the finished attribute as well. Further, I will have additional queries like Book.best_sellers that I would also like to scope to a given user so that they also include the finished attribute.
From my limited exposure to ActiveRecord, it appears there's probably an elegant way to manage this and generate efficient queries, but I have yet to find an example that clarifies this scenario.
EDIT: to clarify, the other queries I'm looking for will not themselves be restricted to books that have been finished, but I need to have the finished attribute appended to each book if it exists for the given book and scoped user in book_viewings.
See my answer here https://stackoverflow.com/a/8874831/365865
Pretty much, no there isn't a specific way to do this, but you can pass a select option to your has_many association. In your case I'd do this:
has_many :books, :through => :book_viewings, :select => 'books.*, book_viewings.finished as finished'

has_many children and has_many parents

I'm trying to figure out a complex relation between a Model.
I have a model called "Concept", which has two inheriting types called "Skill" and "Occupation". Basicly this means that each concept represents a category, but a concept can also be a skill or an occupation when going deep enough into the hierychal tree.
I'm solving this hierachy by using STI. So my schema for the Concepts table looks like this:
class CreateConcepts < ActiveRecord::Migration
def self.up
create_table :concepts do |t|
t.string :uri, :null => false, :length => 255
t.string :type, :null => true, :length => 255
t.integer :isco_code, :null => true
t.timestamps
end
end
def self.down
drop_table :concepts
end
end
The type column determins whether the Concept is a real "Concept" or a "Skill"/"Occupation".
The problem now however the following relations:
EDIT:
A Concept can belong to a single parent Concept
An Occupation can belong to a single parent Concept
A Skill can belong to multiple parent Concepts
A skill has no children
An occupation has no children
so basicly you'd have something like this:
> concept1
> concept2 concept3
> concept4 concept5 concept6 concept7 skill1
> occup1 skill2 occup2 skill5
> occup7 skill2 occup3 skill4
> occup4 skill1 occup8
I hope the picture is a bit clear what I'm trying to explain.
Currently I have created the following migration to try to solve the parent-child relation but I'm not sure how to map this with the associations...
class CreateConceptLinks < ActiveRecord::Migration
def self.up
create_table :concept_links do |t|
t.integer :parent_id, :null => false
t.integer :child_id, :null => false
t.timestamps
end
end
def self.down
drop_table :concept_links
end
end
What I want to end up with is the following posssibilities:
concepta.parents => a Concept object
conceptb.children => an array of Conept objects
Occupation.parents => a Concept object
Occupation.children => []
Skill.parents => an array of Concept objects
Skill.children => []
Hope this is even possible...
You can model hierarchical relations in rails. You've got most of the way there with your migrations. Adding the relations below should allow you to do the method calls you'd like:
def Concept < ActiveRecord::Base
has_many :child_links, :class_name => 'ConceptLink', :foreign_key => 'parent_id'
has_many :children, :through => :child_links
has_many :parent_links, :class_name => 'ConceptLink', :foreign_key => 'child_id'
has_many :parents, :through => :parent_links
end
def ConceptLink < ActiveRecord::Base
belongs_to :child, :class_name => "Concept"
belongs_to :parent, :class_name => "Concept"
end
I'd also take a look at this blog posting which does a very good of explaining parent-child mappings in rails.

Resources