Given Following Models
class User
has_many :conversations
end
class Conversation
belongs_to :user
has_many :messages
end
class Message
belongs_to :conversation
end
I want to remove the Conversation model and migrate the reference to a user to Message.
Normally I would use something like
add_column :messages, :user_id, :integer
Message.reset_column_information
Message.all.each do |message|
message.user_id = message.conversation.user_id
end
remove_column :messages, :conversation_id
But in Production migrations run after the code was updated. Therefore this would throw an error.
Probably I just need a little hint.
Message should still have 'conversation_id' as a field even though you removed the belongs: to relationship right?
So what if you did:
message.user_id = User.find_by_id(message.conversation_id).user_id
A good solution is to define a temporary model inside the migration -> Source: Rails Guides
Related
Trying to get my head around the correct tables and associations for a user model to be related in such a way that a user can be both the buyer and receiver of gifts to/from other users. Each user should only be a buyer for one other user and only be a receiver from one other user.
It looks like you just need a simple migration with a couple of validation.
rails generate migration AddSantaRefToUsers
Edit migration to be:
class AddSantaRefToUsers < ActiveRecord::Migration
def change
add_column :users, :santa_id, :integer
add_index :users, :santa_id
end
end
Run migration rake db:migrate then update your User model.
class User
has_one :santa, foreign_key: 'santa_id'
belongs_to :santa, class_name: 'User'
validate :can_be_santa
validates :santa_id, uniqueness: true # this means no duplicate Santas
private
def can_be_santa
if self.santa == self
self.errors.add(user_id:, "You can't be your own Santa!")
end
end
end
Then making someone another user's Santa should be as easy as:
user1.santa = user2
I wrote a rails program for a non-profit to help track encounters. Originally the thought was that a single encounter might deliver multiple services, hence the setup:
class Encounter < ApplicationRecord
has_many :encounters_services, dependent: :destroy, inverse_of: :encounter
has_many :services, through: :encounters_services
accepts_nested_attributes_for :encounters_services
class Service < ApplicationRecord
has_many :encounters, :through => :encounters_services
has_many :encounters_services, dependent: :destroy, inverse_of: :service
The end user has now figured out that they only want to associate a single service with an encounter. But there's already a lot of data in the database under the original structure. Is there a clean way to convert it to a scenario where a Service "has many" Encounters, and an Encounter "belongs to" a Service, without messing up the data that's already stored in the database in the "EncounterServices" table?
Thanks! I'm still a newbie so I appreciate the help!
I guess you could add a new migration to add a new column to the services and add a little script to set the value from EncountersServices.
Something like
def change
add_column :services, :encounter_id, :integer, index: true
Service.each do |s|
s.update_column :encounter_id, s.encounters.first.id
end
end
You can leave the previous data untouched. Since the old association's data has it's own table, your models' tables won't have garbage.
EDIT: I understood the relationship the wrong way, if an encounter should belong yo a service, the migration would look like this:
def change
add_column :encounters, :service_id, :integer, index: true
Encounter.each do |e|
e.update_column :service_id, e.services.first.id
end
end
I'm working with Rails, and when setting up some tests I encountered:
ActiveModel::MissingAttributeError:
can't write unknown attribute `group_id`
I'm guessing the issue is in my relations. I have
class Group < ActiveRecord::Base
has_many :transactions
has_many :users
end
And
class Transaction < ActiveRecord::Base
belongs_to :group
belongs_to :user
end
And lastly,
class User < ActiveRecord::Base
belongs_to :group
has_many :transactions
end
I saw that someone had the same error because they were using has_one rather than belongs_to and needed to add an ID column to their DB. I'm using belongs_to though, so I don't think that's what I need? Any ideas?
Looks like you don't have the group_id column in your db.
You must remember that Rails is built on top of a relational database, which means that you can access "related" data by referencing a foreign_key.
When setting up a belongs_to / has_many association, the belongs_to table needs to have the appropriate foreign key (in your case group_id):
Your error doesn't state which model you're receiving the exception for; I would hazard a guess that it's User or Transaction.
--
To fix it, I would recommend creating a migration to add the group_id attribute to the appropriate model:
$ rails g migration AddGroupId
#db/migrate/add_group_id____________.rb
class AddGroupID < ActiveRecord::Migration
def change
add_column :users, :group_id, :integer
end
end
$ rake db:migrate
Unless you created the model you are referring to with a migration that had references, you will still need a migration in your database. An easy way to check if the database has one is to visit your some_project_root/db/schema.rb. If you don't see a the field you want there then you will have to generate one. The way you would do so is to run a rails g migration AddXidToY x_id:integer . It should set a field up for the id in the table you want.
How can I migrate the Referral table to point to point to the PatientProfile id instead of the User id for an existing database (i.e. would like to migrate all existing rows)?
class User
belongs_to :profile, polymorphic: true
has_many :referrals
class PatientProfile
has_one :user, as: :profile
class Referral
belongs_to :user
I could accomplish this by simply making a migration and renaming the user_id column to be patient_profile_id and changing the reference in the model, however that would not migrate over existing records.
I wouldn't simply change the column name. I'd do something like this
class AddPatientProfileToReferrals < ActiveRecord::Migration
def up
add_column :referrals, :patient_profile_id
add_index :referrals, :patient_profile_id
Referral.reset_column_information
Referral.includes(:user).find_each do |referral|
referral.update_attribute(:patient_profile_id, referral.user.profile_id)
end
remove_column :referrals, :user_id
end
end
You probably want to make sure the referrals have a user, and you can simply reverse the process to write the down method.
I'm getting stuck at trying to update an existing many to many record.
Project model:
class Project < ActiveRecord::Base
belongs_to :assignment
belongs_to :programmer
end
Programmer model:
class Programmer < ActiveRecord::Base
has_many :projects
has_many :assignments, :through => :projects
end
Assignment model:
class Assignment < ActiveRecord::Base
has_many :projects
has_many :programmers, :through => :projects
end
so I have data linked up like so:
p = Programmer.create(:name => "Mike")
p.assignments.create(:name => "homework4")
p.assignments[0] = Assignment.find_or_create_by_name("homework1")
p.save
so as you can see, I'm trying to update the association of Mike's first hw to "homework1". All the homework assignments are already in the assignments table so it shoud just find "homework1" and assign it to mike. unfortunately, when I type the third line there are no errors, but it doesn't update it. In memory, p.assignments == homework1, but in the DB it's still the same(even after p.save). The project's join table isn't changed at all.
the logs of mysql show this command being generated whenever I enter the 3rd line.
SELECT "assignments".* FROM "assignments" WHERE "assignments"."name" = 'homework1' LIMIT 1
there's no Update anywhere.... what am I doing wrong?
UPDATE
So I found out that I could just reference the join table directly to edit the links. Something along the lines of:
proj = p.projects.first
proj.assignment_id = 12
proj.save!
If you just want a reference to the object, then you need to edit your migration scripts (db/migrate). An example:
def self.up
create_table :configurations do |t|
t.string :name
t.references :project # This store just the id of the object.
t.timestamps
end
end
Don't forget to type:
rake db:migrate