Ruby on Rails - Missing Attribute Error as a result of association - ruby-on-rails

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.

Related

How to update has_many :through table?

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

Rails doesn't respect model associations for has_one

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/

Update attributes of parent model?

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.

Restrict access to "destroy" feature in Ruby on Rails app

Thanks in advance for your help! I have a site built in Ruby on Rails (2.3.15, 1.8.7) that lets people create itineraries to different locations and with different activities at each location. The site has a way of ensuring that the current user can only delete the itineraries associated with his account. The code in itineraries_controller.rb to do this looks something like this:
def destroy
#itinerary = Itinerary.find(params[:id])
if #itinerary.user_id == current_user.id
#itinerary.destroy
respond_to do |format|
format.html { redirect_to('/home') }
format.xml { head :ok }
end
else
redirect_to '/'
end
end
This system works well. I want to do the same thing for the activities, however. In the activities_controller, I want to ensure that the current user can only delete the activities associated with his account.
Currently, here are my four models (with unnecessary stuff stripped out):
User.rb
class User < ActiveRecord::Base
has_many :itineraries
end
Itinerary.rb
class Itinerary < ActiveRecord::Base
has_many :locations
belongs_to :user
end
Location.rb
class Location < ActiveRecord::Base
belongs_to :itinerary
has_many :activities
end
Activity.rb
class Activity < ActiveRecord::Base
belongs_to :location
end
Here is where I'm starting with activities_controller.rb. FYI, my current_user.id is created by an authenticated_system.rb, so don't worry about that part.
def destroy
#activity = Activity.find(params[:id])
if #itinerary.user_id == current_user.id
#activity.destroy
respond_to do |format|
format.html { redirect_to("/") }
format.xml { head :ok }
end
else
redirect_to '/'
end
end
I tried to connect the models using a has_many :through approach, but I didn't know how to do it for more than three models, and I wasn't sure that was the right approach anyway. Thanks again for any help you can provide!
You can simply do
if #activity.location.itinerary.user_id == current_user.id
You really only need to ask the activity for its location, then ask the location for its itinerary, than ask it for its user. It's a bit of a violation of the Law of Demeter, but it will work.
loc = #activity.location
itin = loc.itinerary
if itin.user_id = current_user.id
...
That should work.

How to associate two foreign key to a post on create

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.

Resources