Rails Association and migration - ruby-on-rails

If I wanted to have a "user_type" column in my "users" table that references to another table called "user_type", how do I write the correct association in rails? For example if my user_type is 1 and 1 is admin in my user_types table, and when I write this in my rails console
user = User.first
user.user_type #I want this to return admin
I've tried with
class AddTypeToUsers < ActiveRecord::Migration[5.2]
def change
add_reference :users, :user_type, foreign_key: true
end
end
But it won't work
thank you in advance

This is how you should define the model associations.
class UserType < ApplicationRecord
has_many :users
end
class User < ApplicationRecord
belongs_to :user_type
end
You should read once this association_basics guide to understand how associations works in Rails.

Related

How do I create migrations for model attributes in rails

I'm having difficulty with bulding attributes within my model. I keep seeing this error
NoMethodError: undefined method `users' for #<ActiveRecord::ConnectionAdapters::SQLite3::TableDefinition:0x00007f9d9ad9df98>
I need attributes that look like this:
#group.rb
class Spree::Group < ActiveRecord::Base
has_many :users
end
#user_decorator.rb
Spree::User.class_eval do
belongs_to :group, class_name: "Spree::Group"
end
For group.rb I ran
rails g model Spree::Group
and I got:
class Spree::Group < ApplicationRecord
has_many :users
end
I'm confused on how to add 'has_many :users' without actually going into the
model and inputting it there.
For the user_decorator I'm not sure what that migration would look like. Any help would be fantastic!
You could call:
rails g model group user:references
which will generates an user_id column in the groups table and will modify the group.rb model to add a belongs_to :user relatonship. Please note, you must to put manually the has_many :groups or has_one :group relationship to the user.rb model.
If you already have the model generated, you could create a migration with the following:
rails g migration AddUserToGroup user:belongs_to
which will generate:
class AddUserToGroup < ActiveRecord::Migration
def change
add_reference :groups, :user, index: true
end
end
the only difference with this approach is, the belongs_to :user relationship in the group.rb model won't be created automatically, so you must create it for your own.

Rename field in relation added to existing model

I want to add relation that user can belongs_to teacher. Teachers are stored in Admins table. Typically it will be nobody (nil), but for active students, I would add a specific person who is their teacher at the moment.
Normally I think could do run such migration:
class AddTeacherToUser < ActiveRecord::Migration
def change
add_reference :users, :admin, index: true
end
end
Then in models, I could add like that:
class User < ApplicationRecord
belongs_to :admin
...
class Admin < ApplicationRecord
has_many :users
...
But I want to have on my user field teacher_id, not admin_id is this possible? can I rename a field in migration or inside my model?
Rails version: 4.2
In Rails 4.2+ you can set foreign keys in the db:
In your migration do:
add_reference :users, :teacher, index: true
add_foreign_key :users, :admins, column: :teacher_id
While in your User model do:
belongs_to :teacher, class_name: "Admin"

Rollback transaction rails console

I have encountered a problem with my rails console when I try to create a new event based on a user. I have a feeling this is a very simple error that I am getting, but I am posting because I am unsure of how I should fix it. Here is the command I tried to run:
user.event = Event.create(:name => "Dummy")
Here is my db file for my event:
class CreateEvents < ActiveRecord::Migration[5.0]
def change
create_table :events do |t|
t.string :name
t.timestamps
end
end
end
Here is my Users database file:
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :name
t.string :email
t.string :event
t.integer :code
t.timestamps
end
end
end
Here is my User.rb file:
class User < ApplicationRecord
has_secure_password
has_many :events
def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
end
Here is my Event.rb file:
class Event < ApplicationRecord
belongs_to :user
end
Its not a simple error. It's quite a few things which are wrong.
If you want a relation where a user can have many events, and an event can belong to many users you need to create a join table. As storing a foreign key on either the users or events table would create a one to many relationship which is probably not what you want.
class User < ApplicationRecord
has_many :user_events
has_many :events, through: :user_events
end
class Event < ApplicationRecord
has_many :user_events
has_many :users, through: :user_events
end
# this is a join model.
class UserEvent < ApplicationRecord
belongs_to :user
belongs_to :event
end
A has_many :through association is often used to set up a many-to-many
connection with another model. This association indicates that the
declaring model can be matched with zero or more instances of another
model by proceeding through a third model.
http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
You can generate the UserEvent model and the migration which creates the join table by running:
rails g model user_event user:belongs_to event:belongs_to
This will create a user_events table with the user_id and event_id foreign key columns. You should also roll back the migration which creates the users table and fix it:
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :name
t.string :email
t.string :password_digest # !!!
t.integer :code
t.timestamps
end
end
end
Note the addition of the password_digest column - this is required for has_secure_password. If you have already run this migration on the production database or committed and pushed it you should instead create separate migrations which fix the errors:
class AddPasswordDigestToUsers < ActiveRecord::Migration[5.0]
def change
add_column(:users, :password_digest, :string)
end
end
class RemoveEventFromUsers < ActiveRecord::Migration[5.0]
def change
remove_column(:users, :event)
end
end
To create an event which is associated with a user you can do:
event = user.events.new(name: "Dummy") # does not persist the record
event = user.events.create(name: "Dummy")
You can all assign records from either end by using the shovel operator:
user.events << event
event.users << user
Is this the right association for me?
My main goal for my application is to make it so a user has partys and
those parties have songs.
A party with only one user sounds pretty lame. However if you want to create a special relationship for the user you can create a separate association:
class User < ApplicationRecord
has_many :user_events
has_many :events, through: :user_events
has_many :owned_events, class_name: 'Event', foreign_key: 'owner_id'
end
class Event < ApplicationRecord
has_many :user_events
has_many :users, through: :user_events
belongs_to :owner, class_name: 'User'
end
class AddOwnerIdToEvents < ActiveRecord::Migration[5.0]
def change
add_column(:events, :owner_id, :integer)
add_foreign_key(:events, :users, column: :owner_id)
end
end
Another way to solve this is by adding a column to UserEvent join model which specifies what the association is. But this is pretty far beyond your skill level.
There is no foreign key in your tables. Supposing you are actually intending to have the models as explained ("event belongs to user"/"user has many events"), you need to add a column user_id to the events table, and not an event string to the users table.
You can create a migration or column definition with migration/model generators using the references type:
rails g model event name:string user:references
or
rails g migration add_user_id_to_event user:references
which will add column and the needed indexes.
Moreover, you have that a user has many events, so there is nothing like
user.event = Event.create
(there is no such method as User#event=) but instead
user.events << Event.create(...)

Ruby On Rails scaffold need to include foreign keys?

I'm learning the basics of ruby on rails and I want to make some simple queries but I have a doubt:
I will have these models:
class Client < ActiveRecord::Base
has_one :address
has_many :orders
has_and_belongs_to_many :roles
end
class Address < ActiveRecord::Base
belongs_to :client
end
class Order < ActiveRecord::Base
belongs_to :client, counter_cache: true
end
class Role < ActiveRecord::Base
has_and_belongs_to_many :clients
end
Now, I will use scaffold to generate all the things, and I want to know if I have to directly put the foreign keys in the scaffols, like:
rails generate scaffold Adress street:string number:integer client_id:integer
Or when I make those associations and then migrate my db they will be implicit?
I don't know if I explain myself in the best way.
Thanks
Yep, there is no reference. You need to either pass the client_id or a reference to Client model, e.g:
rails generate scaffold Address street:string number:integer client_id:integer:index
or
rails generate scaffold Address street:string number:integer client:references
Either, in rails 4 you can use belongs_to this way:
Assume that you have a user model in your application
rails g scaffold comment belongs_to:user text:string
it generates that class in your migrate folder:
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.string :text
t.belongs_to :user, index: true, foreign_key: true
t.timestamps null: false
end
end
end
you should execute rake db:migrate then, this command create user_id properties as a index column in your database table.

How best to do in this situation?

I have tree model Meeting , Client, Contact.
When i create new meeting, i can select client or contact , but how better store this structure and association? !Use case client_id and contact_id in meeting table not good.
We assume someone (a creator) can create a meeting. The creator may be a client or a contact.
For that you need a "creator_type" and "creator_id" column on your Meetings Table first, so add an migration using script/rails generate migration AddTypeToMeetings
Then edit the migration file like:
class AddTypeToMeetings < ActiveRecord::Migration
def self.up
add_column :meetings, :creator_id, :integer
add_column :meetings, :creator_type, :string
end
end
Second, you have to adapt your models:
meeting.rb
class Meeting < ActiveRecord::Base
# polymorphic association
belongs_to :creator, :polymorphic => true
end
client.rb
class Client < ActiveRecord::Base
has_many :meetings, :as => :creator
end
contact.rb
class Contact < ActiveRecord::Base
has_many :meetings, :as => :creator
end
How to use:
#my_meeting = Meeting.new
#my_meeting.creator = #my_client
# or if you want a contact:
#my_meeting.creator = #my_contact
You can read more up on polymorphic associations here:
ASCII Casts
Documentation (scroll to Polymorphic Association)

Resources