Newbie: access attributes of model object - ruby-on-rails

I have two model classes: Cars and Customers,
Model Cars:
class car < ActiveRecord::Base
#car has attribute :town_code
has_many :customers
end
Model Customers:
class customer < ActiveRecord::Base
# customer has attribute :first_name, :last_name
belongs_to :car
end
In my controller, I have the following code:
my_customer = Customer.find_all_by_first_name('John')
p my_customer.last_name
p my_customer.car_id
But I got no attribute 'car_id' error, I also got no attribute 'last_name' error.
---Question 1:---
I checked my database, I do have 'car_id' and 'last_name' columns on my customer table. Why I can not access them in the way how my controller code does?
---Question 2:---
but the code : my_customer.map(&:car_id) is working for accessing car_id, however, I do not quite understand the code .map(&:car_id), what does it do? Can anyone explains to me?

The reason you aren't able to do my_customer.last_name is that my_customer is not a Customer here but an array of Customers, since you did find_all. That's also why my_customer.map(&:car_id) works. What that bit of code means is: For each object in the array my_customer, call the method car_id and insert the results into a new array -- and return that new array.
If customer belongs to car, you need a car_id in the customer table (which corresponds to an id column in the car table). Also, you shouldn't have last_name in the car table, but rather in the customer table.
It sounds like you may need to step back and gain a better understanding of ActiveRecord associations. It's not clear to me why a customer would belong_to a car, anyway.

Related

Ruby on Rails -- validating a unique record, not just unique attributes of a record

This might be a very question, but I'm trying to allow only unique records for a table called "Favorites" with attributes "lightbulb_id" and "student_id." I know about model validations
class Person < ActiveRecord::Base
validates_uniqueness_of :user_name
end
But, I want to validate the uniqueness of the entire record (so the combination of lightbulb_id and student_id). So, lightbulb_id and student_id can be duplicated (a student can "favorite" multiple lightbulb_id's) and consequently the same student_id can appear multiple times in the Favorites table with different lightbulb_ids. But the specific combination shouldn't be duplicated (a student cannot favorite a lightbulb twice)
This might be a very basic question, any suggestions would be appreciated. Thanks.
You can try following validation rule:
validates_uniqueness_of :student_id, scope: [:lightbulb_id]

Adding a JOIN between two tables

Here is the classes I have:
Model Organization
has_many Students
Model Student
has_many Classes
belongs_to Organization
Model Class
a field named : price
belongs_to Student
scope :top_expensive_classes, joins(:students).order('price DESC')
Now I want to list the top 10 expensive classes
At least the first problem I have is that in the params I have the organization_id to filter based on that But I write my controller like this which does NOT work because it thinks it should find organization_id in the Class model but it is in the Student model.
#results = Class.top_expensive_classes.where(organization_id: params[:id]).limit(RESULT_SET_COUNT)
So I was wondering if there is a way to fix this? I think I should introduce a new join somewhere? but couldn't figure it out.
There's a typo in your scope: joins:(:programs) should be joins(:programs)
To fetch based on the organization id in Student you may be able to do this:
#results = Class.top_expensive_classes
.joins(student: :organization)
.where(organization: {id: params[:id]})

Proper Rails Association for this setup

Just starting out with rails and I have a question. My grasp on associations is weak.
Lets say I have a model Cars
some cars will be rentals and some will not. So I created a table and a model called Rentals
which just has the car_id in it, designating that at car_id is a rental.
Right now I have a belong_to :cars line in my Rental model. And I'm not sure that's right. I am attempting to get a list of all the rentals easily. So grabbing the car_ids from the rental table and getting all the car information from the cars table the most efficient way.
Can someone help out?
The following:
Car.joins(:rentals).all # try with :rental if not working
Will output all the cars that have a rental object associated with ;)
It depends on what you will exactly need to do with it.
For simplicity, this is how I would do it.
class CarType #better than Rentals and more meaningful [:type => [rental, lease, own]]
belongs_to :car
end
class Car
has_one :car_type
end
So, now for the cars table, it will have a car_type_id pointing to the type in car_types table.

Using Retrieval Multiple Objects for another Retrieval in Active Records/Ruby on Rails

Kind of new to Ruby/Rails, coming from c/c++, so I'm doing my baby steps.
I'm trying to find the most elegant solution to the following problem.
Table A, among others has a foreign key to table B (let's call it b_id), and table B contains a name field and a primary (id).
I wish to get a list of object from A, based on some criteria, use this list's b_id to access Table B, and retrieve the names (name field).
I've been trying many things which fail. I guess I'm missing something fundamental here.
I tried:
curr_users = A.Where(condition)
curr_names = B.where(id: curr_users.b_id) # fails
Also tried:
curr_names = B.where(id: curr_users.all().b_id) # fails, doesn't recognize b_id
The following works, but it only handles a single user...
curr_names = B.where(id: curr_users.first().b_id) # ok
I can iterate the curr_users and build an array of foreign keys and use them to access B, but it seems there must be more elegant way to do this.
What do I miss here?
Cheers.
Assuming you have following models:
class Employee
belongs_to :department
end
class Department
has_many :employees
end
Now you can departments based on some employee filter
# departments with employees from California
Department.include(:employees).where(:employees => {:state => "CA"}).pluck(:name)
For simplicity, let's take an example of Article and Comments, instead of A and B.
A Comment has a foreign key article_id pointing at Article, so we can setup a has_many relationship from Article to Comment and a belongs_to relationship from Comment to Article like so:
class Article < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :article
end
Once you have that, you will be able do <article>.comments and Rails will spit out an array of all comments that have that article's foreign key. No need to use conditionals unless you are trying to set up a more complicated query (like all comments that were created before a certain date, for example).
To get all the comment titles (names in your example), you can do <article>.comments.map(&:title).

Related to result of eager loading in ROR Active Record

I have an Invoice model which belongs to Customer (and of course Customer has_many invoices).
If I do:
{
#invs = Invoice.find(
:all,
:include => ["customer"],
:conditions => ['somecondition']
)
}
The class of #invs is an Array and I can see all the attributes for the 6th invoice in the array if I do: #invs[5]. However at that point I don't see the associated Customer record attributes. To get that I need to do #invs[5].customer.
My question is what is the Ruby structure that allows access to the customer record from the invoice record? I want to create a new arbitrary record of SomeClass and attach that to the invoice record within the recordset so that I can do #inv[5].someclass. Is that possible? and if so how?
[EDIT - FULL STORY]
The following tries to explain why I'm asking the question.
Although my Invoice model relates to a single table in the Db my Customer record can get archived and moved to another table called Archcustomer which is identical to Customer in structure. So I have additional associations like Invoice belongs_to Archcustomer and Archcustomer has_many Invoices.
I need to get a list of Invoices together with their associated customer record (regardless of where it's held i.e. Customer or Archcustomer) but sorted by Customer.category_id and Customer.id and Invoice.id.
In my original example above of #invs I am including the customer record and I could include the :order => 'customer.category_id, customer.id, invoice.id' clause but where the customer is archived the customer record is nil.
So I thought I would do the following:
{
#invs.each do |inv|
next if inv.customer != nil
archcust = Archcustomer.find(inv.customer_id) #since it's not in customer get it from Archcustomer
inv.customer.category_id = archcust.category_id
etc...
...
end
}
and then use #inv.sort_by. However that complains because I'm trying to allocate a value to customer.category_id of Nil class.
That's when I thought if I could attach an arbitrary record to Invoice I could fill in the info from either Archcustomer or Customer and have a common set of attributes to call my sort_by on.
Of course if there is some other way of achieving my set of Invoices ordered as I want them then I'll be happy to go with that.
In your invoice model (assuming you have your Archcustomer relationship in place):
class Invoice < ActiveRecord::Base
def customer_record
customer or archcustomer
end
end
Use #invoice.customer_record instead of #invoice.customer or #invoice.archcustomer when you need to get a record from any available source. .include both when you're loading.
Don't bother assigning stuff to an imaginary Customer when you already have a real Archcustomer. Just run sort_by on customer_record.category_id.

Resources