Rails: Connecting Model to another Model - ruby-on-rails

I just created new columns in my database for my micropost table and these columns were vote_count comment_count and I want to connect it to the Vote models vote_up count and the Comment models comment count. Since I just added these columns although there were votes and comments, how do I connect these other models to the micropost model to fill in the new columns. Any suggestions are much appreciated!
Micropost Model
class Micropost < ActiveRecord::Base
attr_accessible :title, :content, :view_count
acts_as_voteable
belongs_to :school
belongs_to :user
has_many :comments
has_many :views
accepts_nested_attributes_for :comments
end

It looks like what you're trying to do is use a counter_cache, which rails supports, but you've got the names of the columns wrong.
You want to add a comments_count and a votes_count column to your database instead of the ones that you have.
Then you can hook it up to your models as follows:
class Micropost< ActiveRecord::Base
attr_accessible :title, :content, :view_count
acts_as_voteable
belongs_to :school
belongs_to :user
has_many :comments, :counter_cache => true
has_many :views
accepts_nested_attributes_for :comments
end
The votes half of it is a bit more tricky since you're using some extra code with your acts_as_votable module, but counter caches are the way that you want to go if I understand you correctly.
Here is more info on them: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

Related

Finding entries in a join table with identical links

In my chat app I have users and chats. The tables for each of these is connected by a join table:
class User < ApplicationRecord
has_and_belongs_to_many :chats_users
has_and_belongs_to_many :chats, :through => :chats_users
end
class Chat < ApplicationRecord
has_and_belongs_to_many :chats_users
has_and_belongs_to_many :users, :through => :chats_users
end
class ChatsUsers < ApplicationRecord
belongs_to :chat, class_name: 'Chat'
belongs_to :user, class_name: 'User'
validates :ad_id, presence: true
validates :tag_id, presence: true
end
And the inverse in chat.rb.
When creating a new chat with a list of participating list of user_ids, I want to first check a chat doesn't already exist with the exact same list of associated user_ids, but I can't work out a sane way to do this. How can this be done?
has_and_belongs_to_many is only used in the case where you do not need a join model (or where you initially think you don't need it) as its headless. Instead you want to use has_many through::
class User < ApplicationRecord
has_many :chat_users
has_many :chats, through: :chat_users
end
class Chat < ApplicationRecord
has_many :chat_users
has_many :users, through: :chat_users
end
class ChatUser < ApplicationRecord
belongs_to :chat
belongs_to :user
# not needed if these are belongs_to associations in Rails 5+
validates :ad_id, presence: true
validates :tag_id, presence: true
end
You may need to create a migration to change the name of your table to chat_users and make sure it has a primary key.
has_and_belongs_to_many uses an oddball plural_plural naming scheme that will cause rails to infer that the class is named Chats::User since plural words are treated as modules. While you can work around that by explicitly listing the class name its better to just align your schema with the conventions.
If your still just messing about in development roll back and delete the migration that created the join table and run rails g model ChatUser chat:belongs_to user:belongs_to to generate the correct table with a primary key and timestamps.
If you want to select chats connected to a given set of users:
users = [1,2,3]
Chat.joins(:users)
.where(users: { id: users })
.group(:id)
.having(User.arel_table[Arel.star].count.eq(users.length))
.exists?
Note that you don't really need to tell ActiveRecord which table its going through. Thats the beauty of indirect associations.

Data modeling of Grandparent, Parent, and Child relationships in Rails

Is it a bad practice to set a model (table) association between both parent and child AND grandparent and child? For example, if I want to easily query a user's projects or a user's tasks, is the following setup recommended? If so, is there a good way to ensure both foreign keys always point to the same user?
Any help will be greatly appreciated.
class User < ActiveRecord::Base
attr_accessible :email, :first_name, :last_name
has_many :projects
has_many :tasks
end
class Project < ActiveRecord::Base
attr_accessible :name, :status
belongs_to :user
has_many :tasks
end
class Task < ActiveRecord::Base
attr_accessible :name, :status
belongs_to :user
belongs_to :project
end
There is nothing wrong with what you are trying to do, in fact rails has already predefined some association methods to help you. Just a couple of modifications and you are good to go
class User < ActiveRecord::Base
attr_accessible :email, :first_name, :last_name
has_many :projects
has_many :tasks, through: :projects
end
By adding the through: :projects to your tasks now means you can access all of a users tasks like so
$user = User.first #or whatever
$user.tasks
=> [AR array of all tasks]
You can play around with it in irb. In addition you don't need belongs_to :user in your Task model. It's already taken care of.
Look at section 2.4 for more details
EDIT: I have made the assumption (based upon your description) that a task belongs to a project, and a project belongs_to a user, and that user's don't have tasks directly, but through projects. If that was wrong, let me know and we'll figure it out from there.

Rails join table record creation

If I have a HABTM join table called, :inventory_items_shopping_lists, how do I create and call records in this table? I do not have a join model. The two joined models are :inventory_items and :shopping_lists. I'd like to be able to have a user add :inventory_items to their :shopping_lists. Thanks in advance!
EDIT
Here are the relevant models and my goal:
class InventoryItem < ActiveRecord::Base
belongs_to :item, :foreign_key => :item_id
belongs_to :vendor
has_many :list_items
end
class ListItem < ActiveRecord::Base
belongs_to :inventory_item, :foreign_key => :item_id
belongs_to :shopping_list
end
class ShoppingList < ActiveRecord::Base
has_many :list_items
belongs_to :user, :foreign_key => :user_id
end
I'm attempting to have a :user add :inventory_items to a :shopping_list where they will become :list_items. list_items have almost identical attributes of :inventory_items, so I will likely just reference those attributes through association than by duplicating the attributes in the :list_items table. Thoughts or suggestions on this? I'm newish to RoR so I appreciate any feedback on any part of this plan. Thanks!
how do I create and call records in this table?
You basically don't with a HABTM association type. If you want to store more state on the join table than you will need to use a standard has_many (and maybe a has_many :through) so you can manipulate the underlying join model.
For this reason I have never been a fan of HABTM and in fact I have a handful of large Rails apps in production and I have never used HABTM myself.

rails model assignment with has_many :through

I just can't figure out how to create a relation with a join table. I've read all the posts about them, but the main error seems to be that in the join table to models should be singular, which I have. I just can seem to create the models correctly and assign them. I have projects with datasets, and projects can have multiple datasets, while a dataset can belong to multiple projects. A dataset can be active or not, which is why I need the has_many through instead of the has_many_and_belongs_to setup.
My model definitions are:
class Project < ActiveRecord::Base
attr_accessible :name, :user_id
belongs_to :user
has_many :activedatasets
has_many :datasets, :through => :activedatasets
end
class DataSet < ActiveRecord::Base
attr_accessible :name, :project_id, :filename, :tempfilename
has_many :activedatasets
has_many :projects, :through => :activedatasets
end
class ActiveDataSet < ActiveRecord::Base
attr_accessible :active, :data_set_id, :project_id
belongs_to :project
belongs_to :dataset
end
When I create a new dataset I've got the project_id in the params, so I'm trying to setup the relationship like below:
class DataSetsController < ApplicationController
def new
#dataset = DataSet.new
#dataset.activedatasets.project_id = params[:project_id]
end
end
The error I'm getting seems famous:
NameError in DataSetsController#new
uninitialized constant DataSet::Activedataset
Can anybody point me in the right direction please?
Thanks for you attention.
You need to use:
has_many :active_data_sets
has_many :data_sets, :through => :active_data_sets
And in the DataSet model:
has_many :active_data_sets
has_many :projects, :through => :active_data_sets
Basically, rails expects you to use underscores to separate words in association names, and converts them to CamelCase. So active_data_sets becomes ActiveDataSet. Rails then uses this to work out which model class the association is with.
You also need to change your controller to this:
class DataSetsController < ApplicationController
def new
#dataset = DataSet.new
#dataset.active_data_sets.build(:project_id => params[:project_id])
end
end
Otherwise you'll get an error because you tried to set the project_id of the active_data_sets collection rather than creating a new ActiveDataSet.

Comment belongs_to one of several models

My scenario is that there are several different models which can have comments. Trying to figure out the relationships:
Post
has_many :comments
Update
has_many :comments
Comment
belongs_to EITHER :post OR :update (but not both)????
Whats the proper way to set up the comment relationships? I want to be able to call Post.comments and Update.comments
Smells like a polymorphic association:
With polymorphic associations, a model can belong to more than one other model, on a single association. For example, you might have a picture model that belongs to either an employee model or a product model.
So you'd want something like this:
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true
end
class Post < ActiveRecord::Base
has_many :comments, :as => :commentable
end
class Update < ActiveRecord::Base
has_many :comments, :as => :commentable
end
You'd have to set up a few things in the database for this to work as well. See the Polymorphic Associations section of the Active Record Associations Guide for details on the columns you'll need.

Resources