Report/Reports on model in rails - ruby-on-rails

Hi I just create a model with relations with other once but I'm surprised about the pluralize option of rails. I mean.
I create the model like this:
rails g model Report name:string....
like I did with:
rails g model Patient name:string...
rails g model Doctor name:string....
Doctor has many Patients so I can go to the console and type:
patient.doctor => gives me the doctor from a patient
doctor.patients => gives me all patients from a doctor (note patients in plural)
And here is the strange thing, I did exactly the same with report and I expect to have the command:
patient.reports (note plural)
But instead of this if I want to retrieve the patient reports I have to do:
patient.report (note singular)... AND IT WORKS!
Does anyone can illuminate my blindness?

The methods to retrieve the related object(s) depends on how you've declared it in the Model.
Some examples:
class Patient < ActiveRecord::Base
belongs_to :doctor # singular
end
class Doctor < ActiveRecord::Base
has_many :patients # plural
end
Then you can do:
patient.doctor # => return the associated doctor if exists
doctor.patients # => return the patients of this doctor if exist
I think you've declared your relation in singular:
# What I think you have
class Patient < ActiveRecord::Base
has_many :report
end
But you should use plural here:
# What I think you should use
class Patient < ActiveRecord::Base
has_many :reports
^
# Make it plural
end

Related

How to use finder methods on join table values?

In my Ruby on Rails app, i've created a join table in my database to link customers and businesses. Now i'm trying to find information on one of the models based on the information in the join table (called "conflicts"):
#customer = Customer.where(customer_id: 1).conflict(s) Or
#customer = Customer.find(1).conflict(s)
I want to find information about the customer (or business) directly tied to a given "conflict", and print that to the browser view.
Error i'm getting now:
undefined method `conflicts' for #
To get conflict through customer you should have following association in Customer model(customer.rb),
has_one :conflict
OR
has_many :conflicts
As per the description provided you have created a join table having the reference of both customers and businesses.
And the error you have provided, it seems like you forgot to associate them in your models.
customer.rb
class Customer < ApplicationRecord
has_many :customer_conflicts
has_many: conflicts, through: :customer_conflicts
end
conflict.rb
class Conflict < ApplicationRecord
has_many :customer_conflicts
has_many :customers, through: :customer_conflicts
end
customer_conflict.rb
class CustomerConflict < ApplicationRecord
belongs_to :customer
belongs_to :conflict
end
Now running the below mentioned queries will work:
#customer = Customer.where(customer_id: 1).conflicts
#customer = Customer.find(1).conflicts

Rails ActiveRecord Associations with one to many

So, I"m not sure how to setup my associations. First, I have a User model (Devise) which has email and password.
class User < AR::Base
end
After that, I have multiple types of User models which contain more details information about the users:
class Doctor < AR::Base
belongs_to: User
end
And:
class Nurse < AR::Base
belongs_to: User
end
And:
class Therapist < AR::Base
belongs_to: User
end
So, I'm not sure how the User model should relate to the others. Is my design flawed?
Thanks for helping a noob.
The easiest way to implement what you are trying to achieve is to have a column on user to assign a role. So you can call the methods like this:
User.add_role(:doctor)
User.has_role?(:doctor)
You can do that using this gem https://github.com/mcrowe/roleable
Another way to implement it is by using ActiveRecord Enum:
http://api.rubyonrails.org/v5.1/classes/ActiveRecord/Enum.html The implementation would look like this:
User.role # => :doctor
User.doctor? # => true
User.therapist! # => true
User.role # => :therapist
I personally prefer using enums.
A complex way to do it would be to use polymorphism. Where you can put User as a polymorphic model. This blog post explains it in great detail. https://robots.thoughtbot.com/using-polymorphism-to-make-a-better-activity-feed-in-rails
Rails DB Associations Documentation Link
add these has_many's to user.rb
#user.rb
has_many :doctor
has_many :nurse
has_many :therapist
and You need to add user_id to doctor, nurse and therapist.
Such as like:
rails g migration add_user_id_to_nurses user_id:integer
rails g migration add_user_id_to_doctors user_id:integer
rails g migration add_user_id_to_therapits user_id:integer
Do not forget rake db:migrate at the end.
The best way to set setup a one-to-many association between these different types of users, with minimal duplicates, would be by setting up User to belong_to these other models Doctor, Nurse and Therapist
First, setup has_many association between these models to the User model
# app/models/doctor.rb
class Doctor < ActiveRecord::Base
has_many: :users
end
# app/models/nurse.rb
class Nurse < ActiveRecord::Base
has_many: :users
end
# app/models/therapist.rb
class Therapist < ActiveRecord::Base
has_many: :users
end
Then, add migrations to add doctor_id:integer, nurse_id:integer and therapist_id:integer to users table.
Then, setup belongs_to association to other ActiveRecord models.
# app/models/user.rb
class User < ActiveRecord::Base
belongs_to: :doctor
belongs_to: :nurse
belongs_to: :therapist
end
With this setup, you can access ActiveRecord data of these models as follows:
# get doctor associated to User.last
User.last.doctor
# get all the users who are patients of Doctor.last
Doctor.last.users
# get the nurse associated to User.last
User.last.nurse
# get all the users who are patients of Nurse.last
Nurse.last.users

Rails 4.2 Polymorphic associations, association name not resolving

I created the migration according the polymorphic rails cookbook. The models have the following relations
class TeachingAssistant < ActiveRecord::Base
belongs_to :ta_type, polymorphic: true
end
class University < ActiveRecord::Base
has_many :teaching_assistants, as: :ta_type
end
In the rails console i am able to do the following
t = TeachingAssistant.create name: 'name'
u = University.create name: 'hogwarth'
t.update ta_type: u
University.last.teaching_assistants.last
But why is it not possible to use the as: :ta_type association name directly;
University.last.ta_type
results for example in undefined method for ta_type. But typing
University.last.ta_type
and tab-completing returns the following list
University.last.ta_type
University.last.ta_type=
University.last.ta_type_id
University.last.ta_type_id=
University.last.ta_type_id?
University.last.ta_type_id_before_type_cast
University.last.ta_type_id_came_from_user?
University.last.ta_type_id_change
University.last.ta_type_id_changed?
University.last.ta_type_id_was
....
Why is this not possible? Is it by design or am i doing something wrong?

has_one to a polymorphic association

I have the following:
class Car < ActiveRecord::Base
has_one :driver
end
class Driver < ActiveRecord::Base
belongs_to :car
has_one :license, :as => :licensable
end
class License < ActiveRecord::Base
belongs_to :licensable, :polymorphic => true
end
i.e., Car has one driver who has one license (license is polymorphic - let's just say in this case since it can be associated with other objects).
In routes.rb I have:
resources :cars do
resource :driver do
resource :license
end
end
I would like to show my license. The "show" in the routes file is:
GET /cars/:car_id/driver/license(.:format) {:action=>"show", :controller=>"licenses"}
In my licenses controller I have:
def show
#license = #licensable.licenses.find(params[:id])
# continues.......
The problem is that even though driver has the relation to license, the #licensable is coming across as Car because of the routes. Car has no relation to license so the code doesn't work. I assume I either have to change my controller or more likely my routes.
Because from the URL you only get the car_id this could work:
#car = Car.find(params[:car_id])
#license = #car.driver.licensable
An alternative is to use a less nested REST interface. Nesting is not really necessary if licenses and cars both have unique ID's.

How to save extra fields in Rails using has_and_belongs_to_many

I have the following structure in my rails application:
class Movie < ActiveRecord::Base
has_and_belongs_to_many :celebs, :join_table => "movies_celebs"
end
class Celeb < ActiveRecord::Base
has_and_belongs_to_many :movies, :join_table => "movies_celebs"
end
class MovieCeleb < ActiveRecord::Base
belong_to :movie
belong_to :celeb
end
Now MovieCeleb has 2 extra fields CastName(string), CastType('Actor/Director). When I save Movie i create celebs also and fill celebs into celebs relation and it save movies_celebs automatically into database. But how can i pass the CastName and CastType to save also.
Please advise
Thanks in advance.
You should use has_many :through instead of has_and_belongs_to_many if you need validations, callbacks, or extra attributes on the join model.
See :
http://guides.rubyonrails.org/association_basics.html#choosing-between-has_many-through-and-has_and_belongs_to_many
Note the following is for Rails v2
script/generate model Movie id:primary_key name:string
script/generate model Actor id:primary_key movie_id:integer celeb_id:integer cast_name:string cast_type:string
script/generate model Celeb id:primary_key name:string
model/movie.rb
class Movie < ActiveRecord::Base
has_many :actors
has_many :celebs, :through => :actors
end
model/celeb.rb
class Celeb < ActiveRecord::Base
has_many :actors
has_many :movies, :through => :actors
end
model/actor.rb
class Actor < ActiveRecord::Base
belongs_to :movie
belongs_to :celeb
end
Test the associations with the ruby rails console in the application folder
>script/console
>m = Movie.new
>m.name = "Do Androids Dream Of Electric Sheep"
>m.methods.sort #this will list the available methods
#Look for the methods 'actors' and 'celebs' - these
#are the accessor methods built from the provided models
>m.actors #lists the actors - this will be empty atm
>c = Celeb.new
>c.name = "Harrison Ford"
>m.celebs.push(c) #push Harrison Ford into the celebs for Blade Runner
>m.actors #Will be empty atm because the movie hasnt been saved yet
>m.save #should now save the Movie, Actor and Celeb rows to relevant tables
>m.actors #Will now contain the association for
#Movie(id : 1, name : "Do Androids..") - Actor(id : 1, movie_id : 1, celeb_id : 1) -
#Celeb(id : 1, name : "Harrision Ford")
>m = Movie.new #make a new movie
>m.name = "Star Wars"
>m.celebs.push(c) #associated the existing celeb with it
>m.save
>movies = Movie.all #should have the two movies saved now
>actors = Actor.all #should have 2 associations
>this_actor = Actor.first
>this_actor.cast_type = "ACTOR"
>this_actor.save
Then you'll probably want to check out Ryan Bates' Railcasts http://railscasts.com #47 (Two Many-to-Many), and #73, #74, #75 (Complex forms parts 1-3).
There's an updated version of the many-to-many form code on the webpage for #75.

Resources