I have the followings tables
break_points
id: integer
break_point_name: string
schedules
id: integer
departure: int -> break_point_id
arrival:int -> break_point_id
departure_date:date
arrival_date: date
Both departure and arrival are breakpoints .
Then Will I to create an association * to * instead?
1.9.3-p547 :004 > s=Schedule.find(1)
Schedule Load (0.1ms) SELECT "schedules".* FROM "schedules" WHERE "schedules"."id" = ? LIMIT 1 [["id", 1]]
=> #<Schedule id: 1, departure_id: 1, departure_date: "2015-01-05", departure_time: 28800, arrival_id: 11, arrival_date: "2015-01-06", arrival_departure: 3600, bus_company_id: 1, created_at: "2014-11-08 22:55:00", updated_at: "2014-11-08 22:55:00">
1.9.3-p547 :005 > s.departure_break_points
BreakPoint Load (0.3ms) SELECT "break_points".* FROM "break_points" WHERE "break_points"."departure_id" = 1
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: break_points.departure_id: SELECT "break_points".* FROM "break_points" WHERE "break_points"."departure_id" = 1
from /home/fernando/.rvm/gems/ruby-1.9.3-p547#ticket_master/gems/sqlite3-1.3.10/lib/sqlite3/database.rb:91:in `initialize'
from /home/fernando/.rvm/gems/ruby-1.9.3-p547#ticket_master/gems/sqlite3-1.3.10/lib/sqlite3/database.rb:91:in `new'
from /home/fernando/.rvm/gems/ruby-1.9.3-p547#ticket_master/gems/sqlite3-1.3.10/lib/sqlite3/database.rb:91:in `prepare'
these are my migrations that generate the tables of the database
class CreateSchedules < ActiveRecord::Migration
def change
create_table :schedules do |t|
t.integer :departure_id
t.date :departure_date
t.time :departure_time
t.integer :arrival_id
t.date :arrival_date
t.time :arrival_departure
t.integer :bus_company_id
t.timestamps
end
end
end
class CreateBreakPoints < ActiveRecord::Migration
def change
create_table :break_points do |t|
t.string :city
t.integer :province_id
t.timestamps
end
end
end
and these are my models
These are my models
class BreakPoint < ActiveRecord::Base
attr_accessible :break_point_name, :city
belongs_to :province
end
class Schedule < ActiveRecord::Base
has_many :departure_break_points,class_name: "BreakPoint", :foreign_key => 'departure_id', :dependent => :destroy
has_many :arrival_break_points, class_name: "BreakPoint", :foreign_key => 'arrival_id', :dependent => :destroy
end
Add two relations in your model , but specify the foreign key
has_many :departure_break_points,class_name: "BreakPoint", :foreign_key => 'departure' :dependent => :destroy
has_many :arrival_break_points, class_name: "BreakPoint", :foreign_key => 'arrival', :dependent => :destroy
Related
I'm trying to use polymorphic relationship with rails 5.
I have difficulties to figure out how to finish my relations.
I have users, who can take reservations for hotels, restaurants, etc.
My purpose is to get hotels name and reservations when calling /users/{id} through API.
Here is my User model :
class User < ApplicationRecord
has_many :reservations, as: :reservable
has_many :hotels, through: :reservations
end
My Hotel model :
class Hotel < ApplicationRecord
has_many :reservations, as: :reservable
belongs_to :users, through: :reservations
end
My Reservation model :
class Reservation < ApplicationRecord
belongs_to :reservable, polymorphic: true
belongs_to :users
belongs_to :hotels
end
Migrations :
User :
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.timestamps
end
end
end
Reservations :
class CreateReservations < ActiveRecord::Migration[5.0]
def change
create_table :reservations do |t|
t.belongs_to :hotel, index: true
t.belongs_to :user, index: true
t.datetime :date_from
t.datetime :date_to
t.timestamps
end
end
end
class ReservationPolymorphism < ActiveRecord::Migration[5.0]
def change
rename_column :reservations, :hotel_id, :reservable_id
change_column :reservations, :reservable_id, polymorphic: true
add_column :reservations, :reservable_type, :string
end
end
Hotel :
class CreateHotels < ActiveRecord::Migration[5.0]
def change
create_table :hotels do |t|
t.string :name
t.string :address
t.string :postal_code
t.string :town
t.timestamps
end
end
end
I just have 1 line in my reservations table :
mysql> select * from reservations;
+----+---------------+-----------------+---------+---------------------+---------------------+---------------------+---------------------+
| id | reservable_id | reservable_type | user_id | date_from | date_to | created_at | updated_at |
+----+---------------+-----------------+---------+---------------------+---------------------+---------------------+---------------------+
| 1 | 1 | Hotel | 1 | 2017-01-12 00:00:00 | 2017-01-15 00:00:00 | 2016-10-19 09:18:01 | 2016-10-19 09:18:01 |
+----+---------------+-----------------+---------+---------------------+---------------------+---------------------+---------------------+
I have no result when using the API.
Here is what I get, using Rails console :
2.2.3 :001 > thomas = User.find(1)
User Load (0.2ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
=> #<User id: 1, first_name: "Thomas", last_name: "Dupont", email: "thomas.dupont#yopmail.com", created_at: "2016-10-18 21:12:12", updated_at: "2016-10-18 21:12:12">
2.2.3 :003 > thomas.reservations
Reservation Load (0.3ms) SELECT `reservations`.* FROM `reservations` WHERE `reservations`.`reservable_id` = 1 AND `reservations`.`reservable_type` = 'User'
2.2.3 :005 > thomas.hotels
NameError: uninitialized constant User::Hotels
So I can see I make basic mistake with rails relations and polymorphism but I really can't find out where I'm wrong.
I think I made a mistake.
I assumed Polymorphism could be use to load other models and their tables (like "morphTo" with eloquent / laravel), whereas it's just to load a model which has no data representation (as described in this post : https://robots.thoughtbot.com/using-polymorphism-to-make-a-better-activity-feed-in-rails )
I guess on viewing your code, you have written extra associations on top of the polymorphic association,
To create a polymorphic association, just the following code is enough. No need to pass extra association inside the model. Please refactor your code as follows,
User model
class User < ApplicationRecord
has_many :reservations, as: :reservable
end
Hotel model :
class Hotel < ApplicationRecord
has_many :reservations, as: :reservable
end
Reservation model :
class Reservation < ApplicationRecord
belongs_to :reservable, polymorphic: true
end
And in the migration file for reservations, add the reservable as below
t.references :reservable, polymorphic: true
Ok i sorted this out :
This is the reservation model :
class Reservation < ApplicationRecord
belongs_to :reservable, polymorphic: true
end
This is the hotel model :
class Hotel < ApplicationRecord
end
And the user model :
class User < ApplicationRecord
has_many :reservations
end
And how I got a results in rails console :
Running via Spring preloader in process 87452
Loading development environment (Rails 5.0.0.1)
2.2.3 :001 > u = User.find(1)
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
=> #<User id: 1, first_name: "Thomas", last_name: "Dupont", email: "thomas.dupont#yopmail.com", created_at: "2016-10-18 21:12:12", updated_at: "2016-10-18 21:12:12">
2.2.3 :002 > u.reservations
Reservation Load (0.3ms) SELECT `reservations`.* FROM `reservations` WHERE `reservations`.`user_id` = 1
=> #<ActiveRecord::Associations::CollectionProxy [#<Reservation id: 1, reservable_id: 1, reservable_type: "Hotel", user_id: 1, date_from: "2017-01-12 00:00:00", date_to: "2017-01-15 00:00:00", created_at: "2016-10-19 09:18:01", updated_at: "2016-10-19 09:18:01">]>
2.2.3 :003 > u.reservations.first.reservable
Hotel Load (0.3ms) SELECT `hotels`.* FROM `hotels` WHERE `hotels`.`id` = 1 LIMIT 1
=> #<Hotel id: 1, name: "HYATT REGENCY HOTEL", address: "3 Place du Général Kœnig", postal_code: "75017", town: "PARIS", created_at: "2016-10-19 08:36:55", updated_at: "2016-10-19 08:36:55">
I'm looking for help debugging an issue with a Rails has_many :through association. I have 3 models, Package, Venue, and my join table, Packagevenue
package.rb
class Package < ActiveRecord::Base
has_many :packagevenues
has_many :venues, through: :packagevenues
end
venue.rb
class Venue < ActiveRecord::Base
has_many :packagevenues
has_many :packages, through: :packagevenues
end
packagevenue.rb
class Packagevenue < ActiveRecord::Base
belongs_to :venues
belongs_to :packages
end
schema for packagevenues table
create_table "packagevenues", force: :cascade do |t|
t.integer "package_id"
t.integer "venue_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Test Case:
Packagevenue.first
Packagevenue Load (0.3ms) SELECT "packagevenues".* FROM "packagevenues" ORDER BY "packagevenues"."id" ASC LIMIT 1
=> #<Packagevenue:0x007fac12209750> {
:id => 1,
:package_id => 2,
:venue_id => 1,
.....
}
[11] webapp » p=Package.find(2)
Package Load (0.2ms) SELECT "packages".* FROM "packages" WHERE "packages"."id" = $1 LIMIT 1 [["id", 2]]
=> #<Package:0x007fac14eae738> {
:id => 2,
.....
}
[12] webapp » v=Venue.find(1)
Venue Load (0.2ms) SELECT "venues".* FROM "venues" WHERE "venues"."id" = $1 LIMIT 1 [["id", 1]]
=> #<Venue:0x007fac1222e488> {
:id => 1,
.....
}
[13] webapp » v.packages
NameError: uninitialized constant Venue::Packages
.....
[14] webapp » p.venues
NameError: uninitialized constant Package::Venues
.....
I thought I did all of the setup correctly, can somebody please let me know why the Uninitialized Constant error keeps popping up?
The likely cause is due to the plurality of the belongs_to symbols in your Packagevenue model. You want those to be singular like so:
class Packagevenue < ActiveRecord::Base
belongs_to :venue
belongs_to :package
end
I'm curious why my has_many :through association is not populated until after my object is saved and reloaded. It seems like all the data should be there for the joins to be constructed.
Schema:
ActiveRecord::Schema.define(version: 20140821223311) do
create_table "cats", force: true do |t|
t.string "name"
t.integer "human_id"
end
create_table "houses", force: true do |t|
t.string "address"
end
create_table "humen", force: true do |t|
t.string "name"
t.integer "house_id"
end
end
Models:
class Cat < ActiveRecord::Base
belongs_to :human, inverse_of: :cats
has_one :house, through: :human
has_many(
:siblings,
through: :house,
source: :cats
)
end
class Human < ActiveRecord::Base
has_many :cats, inverse_of: :human
belongs_to :house, inverse_of: :humans
end
class House < ActiveRecord::Base
has_many :humans, inverse_of: :house
has_many :cats, through: :humans
end
I've saved an instance of House and Human in the db. The seed file looks like this:
h = House.create(address: "123 Main")
Human.create(house_id: h.id, name: "stu")
I've been testing with this:
c = Cat.new(human_id: 1, name: "something awesome")
p c.siblings # => #<ActiveRecord::Associations::CollectionProxy []>
c.save
p c.siblings # => #<ActiveRecord::Associations::CollectionProxy []>
c.reload
p c.siblings # => #<ActiveRecord::Associations::CollectionProxy [#<Cat id: 2, name: "gizmo", created_at: "2014-08-21 22:37:07", updated_at: "2014-08-21 22:37:07", human_id: 1>]>
Any help on this would be greatly appreciated :)
here's a github repo if you want to play with it:
https://github.com/w1zeman1p/association_wat
It seems CollectionProxy is a bit too lazy. If you do:
c = Cat.new(human_id: 1, name: "something awesome")
c.save
c.siblings
You get what you expect.
So it might be the CollectionProxy being cached from your first call to .siblings before the cat is saved.
I'm new to Rails and I'm having an issue with models using "different" primary/foreign key naming conventions than supported by Rails. (OK, I think this MIGHT be the problem)
So these are my 2 models:
class Project < ActiveRecord::Base
self.primary_key = "PROJECT_ID"
has_many :employees, :foreign_key => "PROJECT_ID"
end
class Employee < ActiveRecord::Base
self.primary_key = "EMPLOYEE_ID"
belongs_to :project, :primary_key => "PROJECT_ID"
end
And this is what's driving me nuts:
> p = Project.find(2)
Project Load (0.2ms) SELECT "projects".* FROM "projects" WHERE "projects"."PROJECT_ID" = ? LIMIT 1 [[nil, 2]]
=> #<Project project_id: 2, name: "Project 2", created_at: "2013-08-18 21:26:33.538007", updated_at: "2013-08-18 21:26:33.538007">
> p.employees.inspect
Employee Load (0.2ms) SELECT "employees".* FROM "employees" WHERE "employees"."PROJECT_ID" = ? **[[nil, nil]]**
=> "#<ActiveRecord::Associations::CollectionProxy []>"
For some reason I don't receive the employees with project_id = 2. It seems that the ? gets substituted with nil.
It works the other way round, check this out
> e = Employee.find_by_project_id(2)
Employee Load (0.2ms) SELECT "employees".* FROM "employees" WHERE "employees"."project_id" = 2 LIMIT 1
=> #<Employee employee_id: 2, first_name: "Will", last_name: "Smith", project_id: 2, created_at: "2013-08-18 21:21:47.884919", updated_at: "2013-08-18 21:22:48.263970">
> e.project.inspect
Project Load (0.2ms) SELECT "projects".* FROM "projects" WHERE "projects"."PROJECT_ID" = ? ORDER BY "projects"."PROJECT_ID" ASC LIMIT 1 [[nil, 2]]
=> "#<Project project_id: 2, name: \"Project 2\", created_at: \"2013-08-18 21:26:33.538007\", updated_at: \"2013-08-18 21:26:33.538007\">"
What am I missing?
Try this:
class Project < ActiveRecord::Base
self.primary_key = "PROJECT_ID"
has_many :employees
end
class Employee < ActiveRecord::Base
attr_accessible :project
self.primary_key = "EMPLOYEE_ID"
belongs_to :project
end
Try to avoid upper case column names at all cost.
for the record here my schema.rb
create_table "employees", :primary_key => "EMPLOYEE_ID", :force => true do |t|
t.integer "project_id"
end
create_table "projects", :primary_key => "PROJECT_ID", :force => true do |t|
end
Try the following:
class Project < ActiveRecord::Base
self.primary_key = "PROJECT_ID"
has_many :employees, :foreign_key => "PROJECT_ID", :primary_key => "PROJECT_ID"
end
class Employee < ActiveRecord::Base
self.primary_key = "EMPLOYEE_ID"
belongs_to :project, :primary_key => "PROJECT_ID", :foreign_key => "PROJECT_ID"
end
If you use uppercased field names (i am not sure based on your question) then make sure you always use uppercased names (e.g. find_by_PROJECT_ID). Rails and ActiveRecord are case sensitive.
I'm not sure what's going on here. I have a scope I'm trying to create that works with my association:
class Subscription < ActiveRecord::Base
belongs_to :subscriber, :class_name => "User"
belongs_to :subscribable, :polymorphic => true
end
create_table :products do |t|
t.string :name
t.decimal :price
t.decimal :cost_per_unit
t.integer :user_id
end
create_table :subscriptions do |t|
t.string :name
t.decimal :price
t.decimal :cost_per_unit
t.integer :subscriber_id
t.integer :subscribable_id
t.string :subscribable_type
end
class Product < ActiveRecord::Base
has_many :subscriptions, :as => :subscribable, :dependent => :destroy
def self.lower_prices
Product.includes(:subscriptions).
where("products.price < subscriptions.price OR products.cost_per_unit < subscriptions.cost_per_unit" )
end
end
I'm trying to compare the lower price of the Product to the Subscription but this gives me the error:
ActiveRecord::StatementInvalid in Pages#subscribed_products
PGError: ERROR: missing FROM-clause entry for table "subscriptions"
LINE 1: ... WHERE (user_id != 2) AND (products.price < subscripti...
^
: SELECT COUNT(*) FROM "products" WHERE (user_id != 2) AND (products.price < subscriptions.price OR products.cost_per_unit < subscriptions.cost_per_unit)
What's wrong here?
The includes method doesn't do exactly what you think. Substitute joins for includes and it should Do What You Mean:
Product.joins(:subscriptions).
where("products.price < subscriptions.price OR products.cost_per_unit < subscriptions.cost_per_unit" )
or perhaps:
Product.includes(:subscriptions).joins(:subscriptions).
where("products.price < subscriptions.price OR products.cost_per_unit < subscriptions.cost_per_unit" )
joins translates to a JOIN in the resulting SQL query, so you can perform WHERE clauses on the joined table. include just asks Active Record to perform another query to select all the related records in the given table. If you do both together, Active Record creates a (rather long) all-in-one that both joins the two tables and uses the results to create both sets of objects.