I am trying to create a model in rails named chat, where I have two columns user1 and user2, and I want to store the user object in these. In grails, I do this simply as
class Chat {
User user1
User user2
Date chatStartedOn
}
and I am done. I did somewhat the same for rails
rails generate model Chat user1:User user2:User chatStartedOn:date
but I run db:migrate it showing me the error
undefined method `User' for #<ActiveRecord::ConnectionAdapters::TableDefinition
my user migrate file
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :username
t.string :email
t.string :encrypted_password
t.string :salt
t.timestamps
end
end
end
Please guide me on how I save user's object in chat table.
Try this
rails generate migration CreateChats
You can then add this code in your Chat migration file
class CreateChats < ActiveRecord::Migration
def change
create_table :chats do |t|
t.integer :user1_id, :references => [:users, :id]
t.integer :user2_id, :references => [:users, :id]
t.date :chatStartedOn
t.timestamps
end
end
end
you would then need to add the associations
Model user.rb
has_one :chat
Model chat.rb
belongs_to :user1, :class_name => "User"
belongs_to :user2, :class_name => "User"
Related
Hi i'm having a problem with a rails association. I have the Table Users and the table Roles. Here are my migrations:
class CreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
t.string :email
t.string :password_digest
t.belongs_to :role, index: true, foreign_key: true
t.timestamps
end
end
end
class CreateRoles < ActiveRecord::Migration[5.2]
def change
create_table :roles do |t|
t.string :name
t.string :code
t.timestamps
end
end
end
Im having the problem when I create a user with a role that I had previously created
Role.create(name: 'Super Admin', code: 'super_admin')
User.create(email: 'a#b.com', password: 'abcdefg', role_id: 1)
When I try to do User.first.role I get that the method role is undefined. As far as i know When i do that i should get an active record with the role.
What i am doing wrong. Please Help
You need to add the relation to your model. In user.rb:
class User < ApplicationRecord
belongs_to :role
# other code
end
It will generate the ActiveRecord methods you are looking for.
I have a Rails project with postgresql database.
Let's say I have three models - Student, Teacher and Schedule - that joins a student and teacher
Student Model - Instead of going with the student_id as my primary key, I want to change that to the even_cooler_unique_student_number that a school has for a student.
Teacher Model - typical & traditional.
Schedule Model - I want to associate a Schedule (think - just a math class for now) with one teacher and its students.
How do I do that at the database level and with the AR associations?
What does changing the primary_key do to the database? To my associations through ActiveRecord?
class CreateStudent < ActiveRecord::Migration
def change
create_table :students do |t|
t.integer :unique_cooler_student_id, null: false
t.string :first_name
t.string :last_name
t.timestamps null: false
end
end
end
class CreateTeacher < ActiveRecord::Migration
def change
create_table :teachers do |t|
t.string :first_name
t.string :last_name
t.string :department
t.timestamps null: false
end
end
end
class CreateSchedules < ActiveRecord::Migration
def change
create_table :schedules, id: false, force: true do |t|
t.belongs_to :students, :primary_key => 'unique_cooler_student_id'
t.belongs_to :teachers
t.string :something_else
t.timestamps null: false
end
end
end
class Student
self.primary_key = 'unique_cooler_student_id'
has_many :teachers, through: :classes
end
class Teacher
has_many :students, through: :classes
end
class Schedule
belongs_to :students
belongs_to :teachers
end
Changing the name of primary key usually does very little besides adding a false sense of security - which is only by obscurity.
You can however change the primary key from a auto-incrementing integer to a hash or some other sort of UUID. And there are many valid reasons to do so. This solely changes the method of generating primary keys.
You can even have separate external UUIDs which are used in url params for example. However this does not involve changing the primary key that ActiveRecord uses to join records:
Foo.joins(:bars).find_by(uuid: 'ABCD')
Of course ActiveRecord will let you crack out the tin-foil hat and use whatever primary keys you want - however you will need to specify the primary_key and probably also manually setup the foreign keys in your database to maintain referential integrity. So basically your losing every advantage of convention over configuration for no benefit.
You would have to do it like this:
class CreateSchedules < ActiveRecord::Migration
def change
create_table :schedules, id: false, force: true do |t|
t.references :students, foreign_key: false
t.belongs_to :teachers
t.string :something_else
t.timestamps null: false
end
end
end
class AddStudensIdContraintToSchedules < ActiveRecord::Migration
def change
add_foreign_key :schedules, :students, primary_key: "unique_cooler_student_id"
end
end
class Schedule
has_many :students, primary_key: 'unique_cooler_student_id'
end
This way AR uses WHERE students.unique_cooler_student_id = 2 in the join query.
The only reason you would ever really want to do this this is if you have to use a legacy database and cannot change the database schema.
I have a problem with copying database records. I have a simple model User, that contains one-to-many relation with Language model and many-to-many relation with Skill model. I wanted to use amoeba gem to copy records with all associations. One-to-many copying works fine, but many-to-many doesn't copy at all.
Here's the code of User and Skill model:
user.rb
class User < ActiveRecord::Base
belongs_to :language
has_and_belongs_to_many :skills
validates_presence_of :email, :name
validates :email,
presence: { with: true, message: "cannot be empty" },
uniqueness: { with: true, message: "already exists in database" }
amoeba do
enable
end
end
skill.rb
class Skill < ActiveRecord::Base
has_and_belongs_to_many :users
end
I have also migration files that crates users, skills and skills_users tables:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name, null: false
t.string :email, null: false
t.references :language
t.timestamps null: false
end
end
end
.
class CreateSkills < ActiveRecord::Migration
def change
create_table :skills do |t|
t.string :name
t.timestamps null: false
end
end
end
.
class AddUsersSkillsTable < ActiveRecord::Migration
def change
create_table 'skills_users', :id => false do |t|
t.column :user_id, :integer
t.column :skill_id, :integer
end
end
end
Controller action 'show' in users_controller looks like this:
def copy
#user_copy = #user.dup
if #user_copy.save(validate: false)
redirect_to action: "index"
end
end
I tried copying relations in user.rb like this, but it didnt work:
amoeba do
enable
clone [:skills]
end
What may cause the problem?
Ok, I found the mistake. I wrote
#user_copy = #user.dup
in the controller file instead of
#user_copy = #user.amoeba_dup
So I am trying to create three models, Project, Entry and User. A Project has many Entries, and a a User has many Entries. I scaffolded the above three models with the following commands:
rails g scaffold Project title:string
rails g scaffold Entry project:project_id entry_for:user_id created_by:userid \
date:string start_time:string end_time:string total:string type_of_work:string \
on_off_site:string phase:string description:text
rails g scaffold User name:string
I realize that I probably totally goofed up the part where I manually put in the foreign keys for the other tables in the Entry model. I don't know how much has_many belongs_to automates the relationship between different models in terms of keys so I tried to add the foreign key fields manually. Is this wrong?
When I try to run db:migrate I get the following error:
undefined method `user_id' for #<ActiveRecord::ConnectionAdapters::TableDefinition:0x007fc1bdf37970>
Here are my migrations, as I tried to remove all of the foreign key fields but got the above error.
class CreateProjects < ActiveRecord::Migration
def change
create_table :projects do |t|
t.string :name
t.timestamps
end
end
end
class CreateEntries < ActiveRecord::Migration
def change
create_table :entries do |t|
t.string :project
t.string :project_id
t.user_id :entry_for
t.user_id :created_by
t.string :date
t.string :start_time
t.string :end_time
t.string :total
t.string :type_of_work
t.string :on_off_site
t.string :phase
t.text :description
t.timestamps
end
end
end
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.timestamps
end
end
end
class RemoveColumns < ActiveRecord::Migration
def self.up
remove_column :entries, :created_by
remove_column :entries, :entry_for
remove_column :entries, :project_id
end
def self.down
add_column :entries, :created_by, :user_id
add_column :entries, :entry_for , :user_id
add_column :entries, :project_id, :string
end
end
Thank you for your help!
In your migrations, instead of t.user_id you can try t.integer or t.index. That should at least get your migrations running.
I am going to use t.references entry_for and then write belongs_to :entry_for, class_name: "User" in the Entry model as a means of writing my own foreign key name. For the project column in entries I realized I can similarly write t.references project.
I'm trying to understand how rails works in respect to foreign key and primary keys. Coming from a pure SQL background the Rails method seems very alien to me.
I have the following two migrations:
Groups
class CreateGroups < ActiveRecord::Migration
def self.up
create_table :groups do |t|
t.string :title
t.text :description
t.string :city
t.integer :event_id
t.string :zip
t.string :group_id
t.text :topics
t.timestamps
end
end
def self.down
drop_table :groups
end
end
and Events:
class CreateEvents < ActiveRecord::Migration
def self.up
create_table :events do |t|
t.string :title
t.string :description
t.string :city
t.string :address
t.time :time_t
t.date :date_t
t.string :group_id
t.timestamps
end
end
def self.down
drop_table :events
end
end
A Group can have many events and an event can belong to a single group. I have the following two models:
class Event < ActiveRecord::Base
belongs_to :group, :foreign_key => 'group_id'
end
and
class Group < ActiveRecord::Base
attr_accessible :title, :description, :city, :zip, :group_id, :topics
has_many :events
end
not sure how to specify foreign keys and primary keys to this. For example a group is identified by the :group_id column and using that I need to fetch events that belong to a single group!
how do i do this!
I see you have group_id and event_id as strings in your migration, so I think you might be missing a rails convention. The rails convention is that all tables have a primary key named id of type integer, and any foreign keys reference it by the name of the model, singular, + _id:
table groups:
id: integer
name: string
table events:
id: integer
name: string
group_id: integer
From this convention, all you have to specify in your models is:
class Event < ActiveRecord::Base
belongs_to :group
end
class Group < ActiveRecord::Base
has_many :events
end
At this point, rails knows what to do by convention over configuration: To find an event's group, it knows to look for group_id (singular) to refer to groups.id (plural table name)
event = Event.first #=> returns the first event in database
group = event.group #=> returns the group object
Similarly, it know how to find all the events in a group
group = Group.first #=> returns first group in database
group.events #=> returns an Enumerable of all the events
For more reading, read the rails guide on associations