I want to get the username of comment author like this
comment.commenter
models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :commenter
belongs_to :commentable, polymorphic: true
end
models/user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates :username, presence: true, uniqueness: true
has_many :comments, as: :commenter
end
When i try to create Comment directly to db using this line of code:
Comment.create(commentable_type: 'Pokemon', commentable_id: 1, content: 'great', commenter: 1)
It throws this error
NameError: uninitialized constant Comment::Commenter
from /var/lib/gems/2.3.0/gems/activerecord-4.2.6/lib/active_record/inheritance.rb:158:in `compute_type'
I've read somewhere as: is used only for polymorphic assocciations so that might be the case of my error but couldn't figure out how to get around this problem
I don't think as: is what you are looking for. I think your issue is similar to the issue in belongs_to with :class_name option fails
Try
# user.rb
has_many :comments, foreign_key: "commenter_id"
# comment.rb
belongs_to :commenter, class_name: "User", foreign_key: "commenter_id"
Let's explain a bit before going to the solution, if you write this code:
belongs_to :commentable, polymorphic: true
It implicitly means:
belongs_to :commentable, foreign_key: 'commentable_id', foreign_type: 'commentable_type', polymorphic: true
And
has_many :comments, as: :commentable
It specifies the syntax of polymorphic, that also means the foreign_key is commentable_id and foreign_type is commentable_type so if you want to change commentable to commenter, it is possible, you can do like this:
class Comment < ActiveRecord::Base
belongs_to :commenter, foreign_key: 'commentable_id', foreign_type: 'commentable_type', polymorphic: true
end
class User < ActiveRecord::Base
has_many :comments, as: commentable
end
That 's it!
For detail, please go through has_many and belongs_to documentation
Related
I have three models and here they are when I try to create a has_many. I basically want my users (using devise) to have many categories. And categories to have many users.
user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable
has_many :user_categories
has_many :categories, through: :user_categories
acts_as_messageable
def mailboxer_email(object)
email
end
end
userCategory.rb
class UserCategory < ActiveRecord::Base
belongs_to :user
belongs_to :category
accepts_nested_attributes_for :categories
end
Category.rb
class Category < ActiveRecord::Base
has_many :user_categories
has_many :user, through: :user_categories
validates :name, presence: true, length: {minimum: 3, maximum: 25}
validates_uniqueness_of :name
end
when I run category.users << user I get this error:
ActiveRecord::HasManyThroughAssociationNotFoundError: Could not find the association :user_categories in model Category
I can't say for sure what the problem could be, but a few things I could point out:
UserCategory's accepts_nested_attributes_for, does that mean the you want to be able to dynamically create categories?
Category has_many :users, through: :user_categories, not user
You need to follow the Rails file naming conventions, user.rb, user_category.rb and category.rb
These may not be the problem/solution, but I believe they're in the way of resolving the problem.
What would be the best way to architect the model relationships and nested resources to build a game with: Users(from devise), Games, Players(join table w/ Games/Users). My problem is Users exist, but Players need to be created at the same time as games. Creating a game also has to create a player, which is possible but feels icky. Is there a better way to do this? I would like to avoid using transactions or filters to create new resources. Thanks.
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable
devise :omniauthable, :omniauth_providers => [:facebook, :twitter]
has_many :games
end
class Player < ActiveRecord::Base
validates :user_id, uniqueness: { scope: :game,
message: "can't join your own game" }
belongs_to :user
belongs_to :game
has_one :board
has_many :ships
end
class Game < ActiveRecord::Base
belongs_to :first_player, class_name: 'Player', foreign_key: 'first_player_id'
belongs_to :second_player, class_name: 'Player', foreign_key: 'second_player_id'
has_one :first_player_board, through: :first_player, source: :board
has_one :second_player_board, through: :second_player, source: :board
end
I ended up solving this by doing away with the player model all together and having Users have_many :games.
class Game < ActiveRecord::Base
belongs_to :first_player, class_name: 'User', foreign_key: 'first_player_id'
belongs_to :second_player, class_name: 'User', foreign_key: 'second_player_id'
has_one :first_player_board, through: :first_player, source: :board
has_one :second_player_board, through: :second_player, source: :board
end
class Message < ActiveRecord::Base
belongs_to :conversation
belongs_to :user
end
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :conversations
has_many :conversations, class_name: "Conversation", foreign_key: :user2_id
end
class Conversation < ActiveRecord::Base
belongs_to :user
belongs_to :user2, class_name: "User", foreign_key: :user2_id
has_many :messages
end
spec:
require 'rails_helper'
RSpec.describe Message, type: :model do
it "should be available to 2 users" do
u = User.create(email: 'x#y.com', password: '8888888888')
u2 = User.create(email: 'z#w.com', password: '8888888888')
c = Conversation.create(user_id: u.id, user2_id: u2.id)
expect(u2.conversations.count).to eq 1
expect(u.conversations.count).to eq 1
end
end
It's this line:
expect(u.conversations.count).to eq 1
that fails.
Presumably because of my second has_many
But if I remove it, then expect(u2.conversations.count).to eq 1 fails.
Yes, I explicitly want only 2 users in a conversation. I was trying to avoid doing HABTM.
How do I make this work?
has_many :conversations
has_many :conversations, class_name: "Conversation", foreign_key: :user2_id
You can only have 1 has_many of a set name. Your first has_many is being overwritten by the second as the ruby class loads. I can't think of a better name but you should name one of them different, maybe something to demonstrate the person initiating the conversation.
You could use a has_many :through with a join model. Here is an explanation of how to set that up: http://www.tweetegy.com/2011/02/setting-join-table-attribute-has_many-through-association-in-rails-activerecord/.
Here is my join model:
class CompanyUser < ActiveRecord::Base
belongs_to :company
belongs_to :user
end
My User model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
ROLES = %w[admin requestor requestor_limited shipping_vendor].freeze
attr_accessor :temp_password
has_many :companies_users
...
end
If I run this in the console:
u = User.first
u.companies
This is the error I am getting:
NameError: uninitialized constant User::CompaniesUser
has_many through relationships should be like this:
In app/models/company.rb file,
has_many :company_users
has_many :users, :through => :company_users
In app/models/user.rb file,
has_many :company_users
has_many :companies, :through => :company_users
In app/models/company_user.rb file,
belongs_to :company
belongs_to :user
If you want to delete the dependent records in company_users table when deleting companies/users,
Add, , :dependent => :destroy at the end of has_many relations in Company and User model.
Hope this helps you..
Thanks.!!
it must be
has_many :company_users
"CompanyUser".tableize => "company_users"
The model shall be either:
class CompaniesUser < ActiveRecord::Base
belongs_to :company
belongs_to :user
end
Or has_many declaration sheel be defined explicitly as:
class User < ActiveRecord::Base
has_many :company_users
end
I have these models:
class Item < ActiveRecord::Base
has_many :item_categoryships
has_many :categories, class_name: 'ItemCategoryship', foreign_key: 'category_id', :through => :item_categoryships
belongs_to :user
validates :title, presence: true
end
class Category < ActiveRecord::Base
has_many :item_categoryships
has_many :items, :through => :item_categoryships
belongs_to :user
validates :name, presence: true
end
class ItemCategoryship < ActiveRecord::Base
belongs_to :item
belongs_to :category
validates :item_id, presence: true
validates :category_id, presence: true
end
class User < ActiveRecord::Base
has_many :items
has_many :categories, class_name: 'Category'
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable, :async
end
But I found when I call item.categories will get a empty array !!! I have checked database, there is a record here.
When I test in the rails console, I didn't get any record back, just saw 'ActiveRecord::Associations::CollectionProxy []'.
What is this? I am using Rails 4.0.2.
Thanks you all.
ActiveRecord::Associations::CollectionProxy is ActiveRecord class for collection associations. Now, your code should work if you change line in Item class describing categories association to:
has_many :categories, through: :item_categoryships