i'm learning Rails and i'm doing an exercise to practice associations and migration files.
Currently, trying to make a models between users, auction item, and bids.
So far for the migrate files I have the following:
class CreateItem < ActiveRecord::Migration
def change
create_table :auction do |t|
t.string :item_name
t.string :condition
t.date :start_date
t.date :end_date
t.text :description
t.timestamps
end
end
end
class CreateBids < ActiveRecord::Migration
def change
create_table :bids do |t|
t.integer :user_id
t.integer :auction_id
t.timestamps
end
end
end
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :email
t.string :username
t.string :password_digest
t.timestamps
end
end
end
These are the following models:
class Bid < ActiveRecord::Base
belongs_to :bidder, class_name: "User", foreign_key: "bidder_id"
belongs_to :auction
end
class User < ActiveRecord::Base
has_many :bids
has_many :auctions, :foreign_key => 'bidder_id'
has_secure_password
end
class Auction < ActiveRecord::Base
belongs_to :seller, class_name: "User", foreign_key: :user_id
has_many :bids
has_many :bidders, through: :bids
end
Any suggestions or opinions? I'm currently trying to test the tables but auctions doesn't seem to be working...
Specifically, my auction table can't seem to find a user_id and therefore a user doesn't have any auctions.
foreign_key refers to the _id (by default) or any unique attribute used to associate the models.
I can't see bidder model, you need to replace them with user_id as they are associated to user model.
Refer for more details belongs_to
class CreateBids < ActiveRecord::Migration
def change
create_table :bids do |t|
t.integer :user_id **do not think this is correct**
t.integer :auction_id **or this one**
t.timestamps
end
end
end
You want to use something more along the lines of the following
class CreateGames < ActiveRecord::Migration[5.0]
def change
create_table :games do |t|
t.integer :total_time
t.references :version, foreign_key: true **#this is how a foreign key should be declared**
t.integer :total_points
t.timestamps
end
end
end
Alternatively, if you want to change things in future migrations you can always add a reference:
def change
add_reference :levels, :version, foreign_key: true
end
Related
I am trying to create an association between a User model and an Attendance model in which an attendee_id references a user. The association is a many to many relationship between users and concerts. The join table attendances has two fields
:attendee and :concert.
seed.rb file:
require 'faker'
Concert.destroy_all
User.destroy_all
Attendance.destroy_all
15.times do
Concert.create(band: Faker::RockBand.name, venue: "#{Faker::LordOfTheRings.location}", date: Faker::Date.forward(rand(30)), start_time: "8:00 PM")
end
5.times do |number|
User.create(first_name: Faker::Name.first_name, last_name: Faker::Name.last_name, email: "#{number}#email.com", password: "password")
end
concerts = Concert.all
users = User.all
15.times do
Attendance.create(attendee: users.sample, concert: concerts.sample)
end
Here are the models:
class Attendance < ApplicationRecord
belongs_to :attendee, class_name: "User"
belongs_to :concert
end
class Concert < ApplicationRecord
validates :band, :venue, :date, :start_time, presence: true
has_many :attendances
has_many :attendees, through: :attendances
end
class User < ApplicationRecord
validates :first_name, :last_name, :email, presence: true
validates_format_of :email, with: /#/
has_secure_password
has_many :attendances, foreign_key: :attendee_id
has_many :concerts, through: :attendances
end
Here are the migrations:
class CreateAttendances < ActiveRecord::Migration[5.0]
def change
create_table :attendances do |t|
t.references :attendee
t.references :concert, index: true
t.timestamps
end
end
end
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :email
t.string :password_digest
t.timestamps
end
end
end
class CreateConcerts < ActiveRecord::Migration[5.0]
def change
create_table :concerts do |t|
t.string :band
t.string :venue
t.datetime :date
t.time :start_time
t.timestamps
end
end
end
Looks like there are no attendee_id column
bundle exec rails db:reset (same as db:drop + db:create + db:migrate + db:seed)
And for tests bundle exec rails db:test:prepare
If it`s not solve the problem, i think, we need moar stacktraces)
I run bundle exec rake db:drop and then I created the database bundle exec rake db:create and bundle exec rake db:migrate I was then able to seed the database.
Please try to change t.references to special alias t.belongs_to.
It worked for me with Rails 5.2.1
I have two models Classification and ClassificationRelationships. I want to create a hierarchy of classifications using supperclass and subclass so that each classification can have many subclasses but only one superclass.
my migrations look like this
class CreateClassifications < ActiveRecord::Migration[5.0]
def change
create_table :classifications do |t|
t.string :symbol
t.string :title
t.integer :level
t.timestamps
end
add_index :classifications, :symbol
add_index :classifications, :level
end
end
class CreateClassificationRelationships < ActiveRecord::Migration[5.0]
def change
create_table :classification_relationships do |t|
t.integer :superclass_id
t.integer :subclass_id
t.timestamps
end
add_index :classification_relationships, :superclass_id
add_index :classification_relationships, :subclass_id
add_index :classification_relationships, [:superclass_id, :subclass_id], unique: true, name: 'unique_relationship'
end
end
so far with my models I have
class ClassificationRelationship < ApplicationRecord
belongs_to :superclass, :class_name => "Classification"
belongs_to :subclass, :class_name => "Classification"
end
class Classification < ApplicationRecord
has_many :classification_relationships
has_many :subclasses, through => :classification_relationships
has_one :superclass, through => :classification_relationships
end
I read quite a few other posts but am still unsure how to finish the associations. I am pretty sure I need to specify the foreign keys but am not clear on how I should do that. Thanks for the help!
Get rid of ClassificationRelationship.
All you need is for Classification to have a parent_id which, in the root instances, is allowed to be null.
Add:
belongs_to :parent, class_name: 'Classification', foreign_key: :parent_id
def children
Classification.where(:parent_id => self.id)
end
Some operations will not be optimal. e.g. Find all descendants. That's because this will require repeated queries to find children, their children, etc...
This may not be a concern for you.
If it is, I recommend storing a path as such:
after_create :set_path
def set_path
path = parent ? "#{parent.path}#{self.id}/" : "#{self.id}/"
self.update_attributes!(:path => path)
end
Then you can do things like:
def descendants
Classification.where("classifications.path LIKE '#{self.path}%' AND classifications.path <> '#{self.path}'")
end
Of course, make sure path is indexed if you'll be doing queries like that.
These are my tables:
create_table :messages do |t|
t.integer :type
t.string :text
t.datetime :sent_date
t.string :sender
t.timestamps
end
create_table :users do |t|
t.integer :phone
t.string :fullname
t.string :profile_image
t.timestamps
end
create_table :send_tos do |t|
t.string :receiver
t.belongs_to :message
t.boolean :is_received
end
and these are the model classes:
class User < ActiveRecord::Base
has_many :send_tos, :foreign_key => 'receiver'
has_many :messages, :foreign_key => 'sender'
end
class Message < ActiveRecord::Base
belongs_to :user, :foreign_key => 'sender'
has_many :send_tos
end
class Send_to < ActiveRecord::Base
belongs_to :user, :foreign_key => "receiver"
belongs_to :message
end
When I run these commands on rails console:
m = Message.new
m.save
s = Send_to.new
s.message = m
s.save
m.send_tos
After command m.send_tos I get this error:
RuntimeError: Circular dependency detected while autoloading constant
SendTo
Why am I getting this error? What should I do to change it?
Change the name of the Send_to class to SendTo. This follows the naming convention that Rails assumes for its relationships. The name of the file it is in should be send_to.rb
Let me explain :
I followed the M. Hartl tutorial and I did just like him with migrations. So now, I have the followings files in my db/migrate directory (I spare you the timestamps):
create_users.rb
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.string :email
t.timestamps
end
end
end
add_index_to_users_email.rb
class AddIndexToUsersEmail < ActiveRecord::Migration
def change
add_index :users, :email, unique: true
end
end
add_password_digest_to_users.rb
class AddPasswordDigestToUsers < ActiveRecord::Migration
def change
add_column :users, :password_digest, :string
end
end
add_remember_token_to_users.rb
class AddRememberTokenToUsers < ActiveRecord::Migration
def change
add_column :users, :remember_token, :string
add_index :users, :remember_token
end
end
add_admin_to_users.rb
class AddAdminToUsers < ActiveRecord::Migration
def change
add_column :users, :admin, :boolean, default: false
end
end
Is it possible to mix everything into create_users.rb like following, and delete the others migration files without any damage to my app ?
create_users.rb
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.string :email
t.string :password_digest
t.string :remember_token
t.boolean :admin, default: false
t.timestamps
end
add_index :users, :email, unique: true
add_index :users, :remember_token
end
end
Yes, it is possible. A straighforward strategy for that might be:
In order to avoid data loss, make a database dumb (create a DB backup)
Drop and recreate the database:
rake db:drop db:create
Have all migrations merged into a single file like you've shown
Run:
rake db:migrate
Restore the DB backup
Though, this may become tricky if you already have the application deployed on production.
I am working on a small Android project with RoR server.
Here are the three models:
class User < ActiveRecord::Base
has_many :relations
has_many :friends, :through => :relations
attr_accessor :friend_ids
end
class Relation < ActiveRecord::Base
belongs_to :user
belongs_to :friend
end
class Friend < ActiveRecord::Base
has_many :relations
has_many :users, :through => :relations
end
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :user_name
t.string :password
t.integer :city_id
t.integer :travelstyle_id
t.boolean :online
t.string :self_description
t.string :sex
t.integer :head_id
t.timestamps
end
end
def self.down
drop_table :users
end
end
class CreateFriends < ActiveRecord::Migration
def self.up
create_table :friends do |t|
t.string :user_name
t.integer :city_id
t.integer :travelstyle_id
t.string :self_description
t.string :sex
t.integer :head_id
t.timestamps
end
end
class CreateRelations < ActiveRecord::Migration
def self.up
create_table :relations do |t|
t.integer :user_id
t.integer :friend_id
t.timestamps
end
end
Model User uses model Relation to connect with model Friend. I use scaffold to creat the three models and add the relationship code in their model files. I also create a API controller to send xml file to Android application. Here is the controller code:
def find_friend
#user=User.where("id=?",params[:id])
#friend=#user.friends
respond_to do |format|
format.html
format.xml
end
end
Here is the problem, when I use the api(type in http://localhost:3000/api/find_friend/1.xml), the server throws a mistake:
NoMethodError in ApiController#find_friend
undefined method `friends' for #<ActiveRecord::Relation:0x3478a28>
app/controllers/api_controller.rb:21:in `find_friend'
I am new to Rails and have no idea where the wrong is. Do I have to add something in the "route.rb" or change the migration file?
In the rails console mode, I type in "user=User.find(1), friend=user.friends" and get the correct result.
~~~~(>_<)~~~~
The problem is the controller method "#user=User.where("id=?",params[:id])". The "where" method can not tell whether the result is an array or actually one object. If I use "#user=User.find(params[:id])", rails will be "smart enough" to know that "Oh, yes, this is just one object and it has a method called Friends because someone connects the two models together".
Learning Rails likes a marriage, you think you know well about her but sometimes you think "God actually I know nothing about the mysterious guy."