User.rb
has_one :subscription, :inverse_of => :user
Subscription.rb
has_one :credit_card, :inverse_of => :subscription
CreditCard.rb
belongs_to :user, :inverse_of => :credit_card
belongs_to :subscription, :inverse_of => :credit_card
In credit card controller:
def new
#credit_card = current_user.build_credit_card
end
def create
#credit_card = current_user.build_credit_card
end
if #credit_card.save
if #credit_card.save
format.html { redirect_to #credit_card, notice: 'Credit card was successfully created.' }
format.json { render action: 'show', status: :created, location: #credit_card }
else
format.html { render action: 'new' }
format.json { render json: #credit_card.errors, status: :unprocessable_entity }
end
end
However, I'm still able to add multiple credit cards to my user model. How can this be possible? Only a has_many should emit such behaviour if I'm correct? A has_one association should prevent additional entities from being created, apart from one as far as I know..
I tried all variations, but still no luck.
Any help would be much appreciated!
Thank you.
I've never used a has_one relationship but the power of google and stack overflow has helped me understand this.
Difference between has_one and belongs_to in Rails?
belongs_to means that the foreign key is in the table for this class. So belongs_to can ONLY go in the class that holds the foreign key.
has_one
means that there is a foreign key in another table that references this class. So has_one can ONLY go in a class that is referenced by a column in another table.
Also a nice way to remember it in that post:
I always think of it in terms of Toy Story. Andy 'has_one' Woody,
Woody 'belongs_to' andy. Where is the foreign key? On Woody's sole.
Also this is useful for understanding relationships.
http://requiremind.com/differences-between-has-one-and-belongs-to-in-ruby-on-rails/
Related
This is a follow up question from one of my earlier questions: How to Model doctor and patient relation
I am fairly new to rails, I am making an appointment booking system between patient and doctor, I have made the relationships, set up authentication using devise. I have 3 models:
class Doctor < ApplicationRecord
has_many :appointments
has_many :patients, through: :appointments
end
class Patient < ApplicationRecord
has_many :appointments
has_many :doctors, through:appointments
end
class Appointment < ApplicationRecord
#table_columns: id | start_time| end_time| doctor_id| patient_id|slot_taken|
belongs_to :patient
belongs_to :doctor
end
I have created the appointments controller: Some actions are below:
#current_doctor comes from devise. Have created two separate models for doctor and patients using devise
def create
#appointment = current_doctor.appointments.build(appointment_params)
respond_to do |format|
if #appointment.save
format.html { redirect_to appointments_path, notice: 'Appointment was successfully created.' }
else
format.html { render :new }
end
end
end
def update
respond_to do |format|
if #appointment.update(appointment_params)
format.html { redirect_to appointments_path, notice: 'Appointment was successfully updated.' }
else
format.html { render :edit }
end
end
end
private
def appointment_params
params.require(:meeting).permit(start_time, end_time)
end
As you can see, the doctor can create the time slots of when he is available, and can edit,update and destroy the same for him/herself and when he creates one the appointment table gets updated with doctor_id, start_time and end_time.
Now, what should I do to add the patient_id and change slot_taken to true (default: false) to it? When the patient books the available slot, the appointments table should be updated with patient_id and slot_taken value. How should I update the appointments table and where should I put the code for the same?
First of all, some advice: I don't think two user models it's a good idea. Think it would be best have one User devise model, and that user have an Role associated for it, so you control the access type by that. If you have to add more type of users to that system, creating one model for each one can be troubling.
About the appointments, question, in a roughly way, if you have an doctor instance, and you wanna make an appointment for some patient at s start_time and e end_time, you can do something like:
doctor.appointments.find_by(start_time: s, end_time: e).update(patient_id: your_patient_id)
About where to put that, depends on how your system works. Is the client that assigns himself? Or some administrator does that?
Anyway, think you should have another action/view for doing that assignment, so you can have a form where the user can input that information, and when he sends the form, you handle it and do the update in some way like a showed before.
Hope this helps, good luck
I have two models.
Company
Memorandum
I want the company to have multiple memorandums and the memorandum to have only one company.
memorandum.rb
class Memorandum < ActiveRecord::Base
belongs_to :company
end
company.rb
class Company < ActiveRecord::Base
has_many :memorandums, dependent: :destroy
# validation lines omitted
end
When I try to assign the foreign key to the memorandum I get a Missing Attribute Error can't write unknown attribute "company_id"
I assign the company inside the companies controller. The memorandum is created prior to this and the id of the current memorandum is held inside the session hash.
companies_controller.rb
def create
#company = Company.new(company_params)
Memorandum.find(session[:memorandum_id]).company = #company
respond_to do |format|
if #company.save
format.html { redirect_to #company, notice: 'Company was successfully created.' }
format.json { render action: 'show', status: :created, location: #company }
else
format.html { render action: 'new' }
format.json { render json: #company.errors, status: :unprocessable_entity }
end
end
end
I strongly recommend you do read the Ruby on Rails Guides for Active Record Association. Concepts are very clearly explained there with example.
Here are two example links: has_many and belongs_to that would help you understand.
To fix your current problem, you need a migration to add company_id to your memorandums table:
rails g migration addCompanyIdToMemorandums company_id:integer
and, then run the migration:
bundle exec rake db:migrate
As the above guide will explain, you need a foreign key in the belongs_to association's table to point it's parent table. As, your memorandums belongs_to company, so you have to add company_id in your memorandums table which we just did using the above migration.
I have been playing around but I cannot seem to figure out how to update the attributes of a parent model.
I have a model called Enhancement and a model called EnhancementComment associated with it. So enhancements can have comments.
I have this successfully working:
EnhancementComments Controller:
def create
#enhancement = Enhancement.friendly.find(params[:enhancement_id])
#enhancement_comment = #enhancement.enhancement_comments.create!(enhancement_comment_params)
respond_to do |format|
if #enhancement_comment.save
format.html { redirect_to #enhancement }
format.json { render action: 'show', status: :created, location: #enhancement_comment }
else
format.html { render action: 'new' }
format.json { render json: #enhancement_comment.errors, status: :unprocessable_entity }
end
end
end
What I want to do: When a comment is created, I want to update the attribute called :updated_at within the Enhancement model (not the EnhancementComment model).
How can I do this?
Thanks.
Updated
Here is what I have now:
class Enhancement < ActiveRecord::Base
# Associations
has_many :enhancement_comments, class_name: 'EnhancementComment', dependent: :destroy
class EnhancementComment < ActiveRecord::Base
# Associations
belongs_to :enhancement, touch: true
This alone doesn't seem to be working when I create a new comment.
Set the touch option to true on the child association. It's explicitly for what you're trying to do, update the updated_at of the opposite end of the association on save.
class Enhancement < ActiveRecord::Base
has_many :comments, class_name: 'EnhancementComment'
end
class EnhancementComment < ActiveRecord::Base
belongs_to :enhancement, touch :true
end
:touch
If true, the associated object will be touched (the updated_at/on attributes set to now) when this record is either saved or destroyed. If you specify a symbol, that attribute will be updated with the current time in addition to the updated_at/on attribute.
I've seen the undefined local variable in many threads, also I have seen adding relationships a lot, so please read the problem before suggesting it's answered elsewhere. (of course, if you do find an answer elsewhere, I will be just as grateful)
The tables are Services and Checks (in the context of a garage, the service is the type and the checks are what need to be carried out for any particular service). This is many to many, so I've got a has many through relationship set up.
The problem is, although everything is working fine, I am still getting the error:
undefined local variable or method `check_ids'
Line:
#service.service_checks.build(check_id: check_ids, service_id: #service.id )
Any attempt I make to define the variable seems to stop the relationships from working. Which leaves me clueless as to how to get everything working in harmony.
Models:
class Service < ActiveRecord::Base
has_many :service_checks, :dependent => :destroy
has_many :checks, :through => :service_checks
#attr_accessor :check_ids
accepts_nested_attributes_for :checks
accepts_nested_attributes_for :service_checks
end
class Check < ActiveRecord::Base
has_many :service_checks
has_many :services, :through => :service_checks
belongs_to :check_cat
end
class ServiceCheck < ActiveRecord::Base
belongs_to :service, dependent: :destroy
belongs_to :check, dependent: :destroy
accepts_nested_attributes_for :check, :reject_if => :all_blank
self.primary_key = [:service_id, :check_id]
end
My update function in Service looks like this:
def update
respond_to do |format|
if #service.update(service_params)
# This builds the relationships
#service.service_checks.build(check_id: check_ids, service_id: #service.id )
format.html { redirect_to #service, notice: 'Service was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #service.errors, status: :unprocessable_entity }
end
end
end
# Never trust parameters from the scary internet, only allow the white list through.
def service_params
params.require(:service).permit(:name, :price, :check_ids => [])
end
And my form is simply:
<%= f.association :checks,
as: :check_boxes,
label_method: :name,
value_method: :id,
label: 'Checks' %>
I think you've got everything setup for this to work OK if you just remove the line for #service.service_checks.build(check_id: check_ids, service_id: #service.id ). The association build is already handled. And once you're past update everything has been saved already.
The reason you're getting an undefined variable error is because check_ids doesn't exist. You are in a context where the params array coming down from the form and the check ids are available in params[:service][:check_ids] if you needed to access them. Note also that if you had to call service_checks.build you would want to pass a single value to the check_id attribute, and not an array like params[:service][:check_ids].
But, again, I think what you really want to try is removing the build line.
It would appear I do not need this line at all.
#service.service_checks.build(check_id: check_ids, service_id: #service.id )
Due to the relationship defined in the model, Rails is magically able to do the rest automatically!
I have 3 models as below and would like to associate two foreign key to a post on create (user_id (from User model) and review_id (from Review model) to Goal model. I manage to associate the user_id using 'current_user' to goals on create by using the solution given in the link below but not sure on how to go about getting this done as well for review_id.
Thanks.
Devise how to associate current user to post?
My models:
class User < ActiveRecord::Base
has_many :reviews
has_many :periods, :through => :reviews
has_many :goals
end
class Review < ActiveRecord::Base
belongs_to :user
belongs_to :period
has_many :goals
end
class Goal < ActiveRecord::Base
belongs_to :user
belongs_to :review
end
My goals_controller.rb
def create
#goal = current_user.goals.build(params[:goal])
respond_to do |format|
if #goal.save
format.html { redirect_to #goal, notice: 'Goal was successfully created.' }
format.json { render json: #goal, status: :created, location: #goal }
else
format.html { render action: "new" }
format.json { render json: #goal.errors, status: :unprocessable_entity }
end
end
end
Cheers,
Azren
While I don't understand what the goal is. One general way I usually use is to model the relationships to something you are familiar with or you can easily find good examples. For example, think about your use case as user-question-answer models. Same as your use case, user has many questions and many answers. question has many answers and belongs to user, and answer belongs to user and question.
So things become easy, right? Let's see how stackoverflow implements this. You can check the html code of a comment box, and the form action is something like (/questions/10186415/answer/submit). Here 10186415 is the question id, it's passed to the server side, so when an answer is created, this question id can be used and related.
Back to your case, the goal form should know what review it's for. The review id could be a hidden field, or part of the submit url.