ActiveRecord: Add foreign key after instance creation - ruby-on-rails

I want to a a foreign key "the rails way" after creation of an instance. How does it work?
Models:
class Letter < ActiveRecord::Base
belongs_to :sender
belongs_to :campaign
end
class Campaign < ActiveRecord::Base
has_many :letters
end
class Sender < ActiveRecord::Base
has_many :letters
end
Code:
sender1 = Sender.first
letter1 = sender1.letters.create
#Now I want to add a connection from letter1 to a campaign,
#but this cannot be the proper rails way:
letter1.campaign_id = 1

Related

Shopping cart Active Record Associations

I am trying to implement a shopping cart within a Rails application. For this, I am trying to glue together these models:
user.rb
class User < ApplicationRecord
has_many :cart_contents
end
cart_content.rb:
class CartContent < ApplicationRecord
belongs_to :user
has_one :product
end
product.rb
class Product < ApplicationRecord
end
To test if this arrangement is working, I tried this in the console:
irb(main):006:0> cc = CartContent.new
=>
#<CartContent:0x000055679d802a28
...
irb(main):008:0> cc.user = User.find(1)
User Load (0.2ms) SELECT "users".* FROM [...]
=> #<User id: 1, email: "mail#example.com", ...
irb(main):010:0> cc.product = Product.find(1)
Product Load (0.1ms) SELECT "products".* FROM [...]
/[...]/activemodel-7.0.0/lib/active_model/attribute.rb:211:
in `with_value_from_database': can't write unknown attribute `cart_content_id` (ActiveModel::MissingAttributeError)
What am I missing here? Do I need to indicate a relationship to cart_content in product.rb?
One possible solution: you may want your CartContent to belongs_to :product.
class CartContent < ApplicationRecord
belongs_to :user
has_one :product # change this to belongs_to
end
cc.product = Product.find(1)
# .. can't write unknown attribute `cart_content_id` (ActiveModel::MissingAttributeError)
has_one will expect your products table to have a cart_content_id column.
See guide section 2.7 Choosing Between belongs_to and has_one
For this, you need to build relations between your models. As mentioned by Jared in this link for the foreign key to exist, you need to specify a belongs_to constraint.
The distinction is in where you place the foreign key (it goes on the table for the class declaring the belongs_to association)
class Product < ApplicationRecord
belongs_to :cart_content
end
If you also want to access all Products for User you can go for below, but you probably don't need a through relation.
class User < ApplicationRecord
has_many :cart_contents
has_many :products, through: :cart_contents
end
Then your Product model would look like this
class Product < ApplicationRecord
belongs_to :cart_content
belongs_to :user
end
I found a solution that works for me.
product.rb
class Product < ApplicationRecord
has_one :cart_content
end
cart_content.rb
class CartContent < ApplicationRecord
belongs_to :user
belongs_to :product
end
user.rb
class User < ApplicationRecord
has_many :cart_contents
has_many :products, through: :cart_contents # for convenience
end
Rails no longer expects a cart_content_id column on Product and the following commands all work in the console:
user = User.first
product = Product.first
cc = CartContent.new
cc.user = user
cc.product = product
cc.save
User.first.products # returns products currently in cart

How to search in Ruby on Rails

I have the three models:
class Joinedtravel < ApplicationRecord
belongs_to :travel
belongs_to :user
end
class Travel < ApplicationRecord
has_many :joinedtravels
belongs_to :user
end
class User < ApplicationRecord
has_many :joinedtravels
has_many :travels
end
How can I obtain all travels that a user has joined in the past?
I did something like that:
#user = User.find(id)
#past_travels = Travel.where('travels.data < ?', DateTime.now)
#all_joinedtravels = #user.joinedtravels.travels
but i don't kwon how to correctly join the results.
First you need to fix the relationship
class Joinedtravel < ApplicationRecord
belongs_to :travel
belongs_to :user
end
class Travel < ApplicationRecord
has_many :users, through: joinedtravels
has_many :joinedtravels
end
class User < ApplicationRecord
has_many :travels, through: joinedtravels
has_many :joinedtravels
end
Then you can simply search it using
User
.find(id)
.travels
.where('travels.data < ?', DateTime.now)
This should work:
#user = User.find(id)
#past_joinedtravels = #user.joinedtravels.joins(:travels).where('travels.date < ?', DateTime.now)
Try this in the console, and pay attention to the sql produced. That will show you possible errors.
The travelsin the joins clause is the model name. The travelsin the where clause must be the literal database table name, which I just guessed.
Seems to me you'd be better off using a has_and_belongs_to_many relations and a join table to join the User and Travel models as long as you're not including any additional information in the JoinedTravel model?
https://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association
class Travel < ApplicationRecord
has_and_belongs_to_many :user
end
class User < ApplicationRecord
has_and_belongs_to_many :travels
end
#user = User.find(id)
#past_travels = Travel.where('travels.data < ?', DateTime.now)
#user_travels = #user.travels
You could then see if a user has any travels:
#user.travels.present?

Namespaced key lookup on Rails 5 association with ActiveRecord

I have the following models:
class Supervision::ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
def self.table_name_prefix
"supervision_"
end
end
---------------
class Supervision::Activity < Supervision::ApplicationRecord
has_one :supervision_missed_visit, class_name: Supervision::MissedVisit
(...)
end
---------------
class Supervision::MissedVisit < Supervision::ApplicationRecord
belongs_to :supervision_activity, class_name: Supervision::Activity
(...)
end
And I also have this model, which isn't namespaced:
class Activity < ApplicationRecord
(...)
end
Whenever I try to reach the Supervision::MissedVisit through its has_one relationship, as in
#supervision_activity.supervision_missed_visit
I get the following error:
ERROR: column supervision_missed_visits.activity_id does not exist
How do I make it so that Rails understands that I'm actually looking for supervision_missed_visits.supervision_activity_id?
You could specify the foreign key:
has_one :supervision_missed_visit, class_name: Supervision::MissedVisit, foreign_key: 'supervision_activity_id'
Another way to do it would be to create an instance method in Supervision::Activity:
def missed_visit
Supervision::MissedVisit.where(supervision_activity_id: id).take
end

How to get value of some column of association table in Rails?

how can I get a weight of product through a Record model? As I know, possible to get all products of certain record but I cannot find out the way getting the weight of certain product.
class User < ActiveRecord::Base
has_many :eatings
end
class Eating < ActiveRecord::Base
belongs_to :user
has_many :records
end
class Record < ActiveRecord::Base
belongs_to :eating
end
class Product < ActiveRecord::Base
end
class WeightedProduct < ActiveRecord::Base
end
What relationships should have Record and Product models with WeightedProduct so user will be able to get weight of certain product through one line User.first.eatings.first.records.first.products.first.weight?
Looks like you're after this:
class Record < ActiveRecord::Base
belongs_to :eating
has_many :weighted_products
end
class Product < ActiveRecord::Base
has_many :weighted_products
end
class WeightedProduct < ActiveRecord::Base
belongs_to :record
belongs_to :product
end
Then User.first.eatings.first.records.first.weighted_products.first.weight
I think that should work but haven't tested.
it seems that each product has one weighted product, then in that case you should add
class Product < ActiveRecord::Base
has_one :weighted_product
end
class WeightedProduct < ActiveRecord::Base
belongs_to :product
end
and
class Record < ActiveRecord::Base
belongs_to :eating
has_many :products
end

Rails Inheritance with relationships problem

I am using single table inheritance in my project. Instead of explaining more, I'll give the code:
# person_profile.rb
class PersonProfile < ActiveRecord::Base
belongs_to :Person
end
# company_profile.rb
class CompanyProfile < ActiveRecord::Base
belongs_to :Company
end
# person.rb
class Person < User
has_one :PersonProfile
end
# company.rb
class Company < User
has_one :CompanyProfile
end
This seems to me like it should work fine. In one of my views I try if #person.PersonProfile == nil which makes perfect sense to me. But Rails doesn't like it:
Mysql::Error: Unknown column 'person_profiles.person_id' in 'where clause': SELECT * FROM `person_profiles` WHERE (`person_profiles`.person_id = 41) LIMIT 1
Rails is looking for person_id in the table person_profiles, but there is only a user_id in that table. What is the best way to fix this bug?
You can use the :foreign_key option of has_one to specify the key.
For example:
has_one :person, :foreign_key => "user_id"
See this reference.
The models specified in your model associations should be in lowercase with each word being separated by an underscore. So:
class PersonProfile < ActiveRecord::Base
belongs_to :person
end
class CompanyProfile < ActiveRecord::Base
belongs_to :company
end
class Person < User
has_one :person_profile
end
class Company < User
has_one :company_profile
end
i had to specify the foreign_key as 'user_id' because it thinks its 'person_id' by default.
class Person < User
has_one :person_profile, :foreign_key => 'user_id'
end
class Company < User
has_one :company_profile, :foreign_key => 'user_id'
end

Resources