Rails4 how to create the model relationship on join table - ruby-on-rails

this is user table:
create_table :users do |t|
t.string :name
t.string :password
t.string :department
t.timestamps
end
this is meet table:
create_table :meets do |t|
t.string :name, null: false
t.string :state, null: false
t.string :description, null: false
t.string :location, null: false
t.float :spend, null: false
t.timestamps
end
The following is a relationship between user and meet:
user can create many meets
a meet can have many participants(users)
I am new to study rails, i tried to create migration and model, But i do not know the correct way:
User can create many meets, I think i can add reference in meets migrate to create a one to one relationship
t.references :users
a meet can have many users, I think i must create a join table:
rails g migration CreateJoinTableUsersMeets user meet
The above command will auto generate a migration file:
create_join_table :Users, :Ploys do |t|
t.index [:user_id, :ploy_id]
t.index [:ploy_id, :user_id]
end
But i want know how to create model relationship on join tabel?

This is how I would do it.
create_table :users do |t|
t.string :name
t.string :password
t.string :department
t.timestamps
end
create_table :meets do |t|
t.string :name, null: false
t.string :state, null: false
t.string :description, null: false
t.string :location, null: false
t.float :spend, null: false
t.references :creator, class_name: "User"
t.timestamps
end
create_table :participations do |t|
t.references :user
t.references :meet
end
add_index :participations, [:user_id, :meet_id]
add_index :participations, [:meet_id, :user_id]
class User < ActiveRecord::Base
has_many :meets, through: :participations
has_many :created_meets, class_name: "Meet", foreign_key: "creator_id"
end
class Meet < ActiveRecord::Base
has_many :users, through: :participations
belongs_to :creator, class_name: "User"
end
You do not create a one to one relationship in the table but you just have to create a join table called participations. That model will have a reference to a user and a meet. Then, you can specify has_and_belongs_to_many by adding the above code to both models. The point is that it uses the join table to create associations. Comment if you have any other question :)

Related

How to create a model without the associated model through a has many relationship

Trying to create a chatroom app, and I'm not sure where to use my associations correctly when creating a chatroom conversation
SCHEMA
create_table "chat_messages", force: :cascade do |t|
t.string "body"
t.integer "user_id"
t.integer "conversation_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "conversations", force: :cascade do |t|
t.string "room_name"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "users", force: :cascade do |t|
t.string "user_name"
t.string "email"
t.string "password"
t.string "password_digest"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
class User < ApplicationRecord
has_secure_password
has_many :chat_messages
has_many :conversations, through: :chat_messages
end
class Conversation < ApplicationRecord
has_many :chat_messages
has_many :users, through: :chat_messages
end
class ChatMessage < ApplicationRecord
belongs_to :user
belongs_to :conversation
validates :body, presence: true
end
I can create a user, and I would like to be able to set the name of a chatroom conversation by using
user = User.first
user.conversations.create(room_name: 'my chatroom')
This prevents me from creating the conversation because the ChatMessage is the through association model, and it needs a body property, but I don't need to create a message when creating the name of the room. I have a hard time understanding how and when to use associations.
I tried adding a user_id to the conversations table, but I'm still confused as to how it works with the other models.
First take a look at the association you have created.
class User < ApplicationRecord
has_secure_password
has_many :chat_messages
has_many :conversations, through: :chat_messages
end
class Conversation < ApplicationRecord
has_many :chat_messages
has_many :users, through: :chat_messages
end
here conversation between conversation and user is through chat_messages
conversation => chat_messages => user
So Creating a conversation with user without chat_messages will break your code.
You can add user_id/admin_id in the conversation table and make changes in associations as below:
class Conversation < ApplicationRecord
has_many :chat_messages
has_many :users, through: :chat_messages
has_one :admin, class_name: 'User',foreign_key: 'user_id'
end
And while fetching you can fetch the user as convesation.admin
Please have a look at the docs here.
I hope this will help you.

PG::UndefinedColumn: ERROR: column services.zip_code does not exist

I have 2 models (Service and Town) with a :has_many :through relationship. I want to be able to find every services of a town and every towns of a service.
Also in front I should never be able to see my Town ID so I can link service and town only with the zip_code of a town.
Here is all my migrations
create_table :services, type: :uuid do |t|
t.string :name, null: false
t.string :action, null: false
t.string :kind, null: false
end
create_table :towns do |t|
t.string :name, null: false
t.stirng :zip_code, null: false
t.string :country, null: false
end
create_table :services_towns do |t|
t.belongs_to :service
t.belongs_to :town
t.string :zip_code, null: false
t.index :zip_code
end
here are my models
class Town < ApplicatonRecord
has_many :services_towns, primary_key: :zip_code, foreign_key: :zip_code
has_many :services, through: :services_communes
end
class Service < ApplicationRecord
has_many :services_towns
has_many :towns, through: :services_communes
end
class ServicesTown < ApplicationRecord
belongs_to :service
belongs_to :town, primary_key: :zip_code, foreign_key: :zip_code
end
#service.towns and #town.services are working well in my rails console but if I try a more complex search like
Service.where(towns: [towns_array]) I got the following error
PG::UndefinedColumn: ERROR: column services.zip_code does not exist
With this request I would like to have every Services from every Towns I have passed in the array.
I guess the problem are because of my primary_key or foreign_key but I don't know what to do better
You need to fix your query, try this
Service.joins(:towns).where(towns: { zip_code: towns_array })
or
Service.joins(:towns).where("towns.zip_code IN (?)", towns_array)
Hope that helps!

Unable to count records for associated model NoMethodError

I tried to multiple ways to get the count of all job applications for the job model, that an employer has. When it comes to one job in particular (job.job_applications.count), it works. You can actually count the applications for that job in question. When you try to sum all job applications for all jobs. I may have overlooked something while setting up the relationships. I receive the error below:
line of code that breaks: <%= current_employer.jobs.job_applications.count %>
undefined method job_applications' for #<Job::ActiveRecord_Associations_CollectionProxy:0x0000000011066998>
The code that I wrote beforehand, is below:
schema
job
create_table "jobs", force: :cascade do |t|
t.string "job_title"
t.text "required_exp"
t.text "job_description"
t.text "job_requirements"
t.bigint "employer_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "slug"
t.bigint "visit_id"
t.index ["employer_id"], name: "index_jobs_on_employer_id"
t.index ["slug"], name: "index_jobs_on_slug", unique: true
end
job applications
create_table "job_applications", force: :cascade do |t|
t.bigint "user_id"
t.string "user_resume_link"
t.string "user_contact_time"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "user_first_name"
t.string "user_last_name"
t.bigint "job_id"
t.index ["job_id"], name: "index_job_applications_on_job_id"
t.index ["user_id"], name: "index_job_applications_on_user_id"
end
job.rb
class Job < ApplicationRecord
belongs_to :employer
has_many :job_applications, dependent: :destroy
has_one :job_category
end
job_application.rb
class JobApplication < ApplicationRecord
belongs_to :user
belongs_to :job
end
employer.rb
class Employer < ApplicationRecord
has_many :jobs, :dependent => :destroy
end
user.rb
class User < ApplicationRecord
has_many :job_applications, dependent: :destroy
has_many :jobs, :through => :job_applications
end
class Employer < ApplicationRecord
has_many :jobs, :dependent => :destroy
has_many :job_applications, through: :jobs
end
And then just call current_employer.job_applications.count

ActiveRecord -- user has_many events and belongs to those events as member

I want to set up a relationship where users can start events and then also join them as members. I figured this uses a many to many relationship, but it also has a simple belongs_to relationship from Event to User.
class User < ActiveRecord::Base
has_secure_password
has_many :events # => Owning
has_many :events, through: :members # => Joining
end
class Event < ActiveRecord::Base
belongs_to :user # => event owner
has_many :users, through: :members # => joining users
end
class Member < ActiveRecord::Base
belongs_to :user
belongs_to :event
end
But I'm having trouble getting queries like Event.first.members to work... I can't figure out what's preventing me from using these methods. Am I thinking of these relationships the wrong way? My Schema.rb:
ActiveRecord::Schema.define(version: 20161205220807) do
create_table "events", force: :cascade do |t|
t.string "title"
t.string "location"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "events", ["user_id"], name: "index_events_on_user_id"
create_table "members", force: :cascade do |t|
t.integer "user_id"
t.integer "event_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "members", ["event_id"], name: "index_members_on_event_id"
add_index "members", ["user_id"], name: "index_members_on_user_id"
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.integer "age"
t.string "password_digest"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
Updated to fix my mistake
class User < ActiveRecord::Base
has_secure_password
has_many :members
has_many :events, through: :members
end
class Event < ActiveRecord::Base
#belongs_to :user # => event owner
has_many :members
has_many :users, through: :members
class Member < ActiveRecord::Base
belongs_to :user
belongs_to :event
end
If this is giving you a stack level too deep error im guessing the issue is elsewhere. Your logs might have more info.

Associations between three models

I have Article model which should have one gallery, and every gallery should have many pictures. Associations between Article-Gallery, Gallery-Picture models work properly, but I have no idea what I'm doing wrong with Article-Picture association. I've attached my code below.
Article.rb model
class Article < ActiveRecord::Base
belongs_to :gallery
has_many :pictures, through: :galleries
end
Gallery.rb model
class Gallery < ActiveRecord::Base
has_many :pictures, dependent: :destroy
has_many :articles
end
Picture.rb model
class Picture < ActiveRecord::Base
belongs_to :gallery
has_many :articles, through: :galleries
end
Schema.rb
ActiveRecord::Schema.define(version: 20150829181617) do
create_table "articles", force: :cascade do |t|
t.string "title"
t.text "content"
t.integer "author_id"
t.integer "language_id"
t.integer "category_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "gallery_id"
end
add_index "articles", ["gallery_id"], name: "index_articles_on_gallery_id"
create_table "galleries", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "pictures", force: :cascade do |t|
t.string "image"
t.integer "gallery_id"
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
In Rails 4 you can certainly state that an Article:
belongs_to :gallery
has_many :pictures, :through => :gallery
... and that a picture ...
belongs_to :gallery
has_many :articles, :through => :gallery
... allowing you to do both:
#picture.articles
... and ...
#article.galleries
... with both of those being executed as a single query joining through the galleries table.
David's answer is right, belongs_to does work for through associations in Rails 4.
class Article < ActiveRecord::Base
belongs_to :gallery
has_many :pictures, through: :gallery # not :galleries
end
The thing to remember is that the through part of a has_one or has_many is referring to an association, not another model. This is important when you're doing trickier associations.

Resources