Joining two tables that share the same id - ruby-on-rails

Let's say I have two tables: NormalClass Table and SpecialClass Table.
Each table contains classes for students.
I want to join tables so that I can access the normal classes of each student in that has a special class for students.
Both tables share the student_id key.
Trying to do this:
NormalClass.includes(:specialClasses)..
results in:
ActiveRecord::ConfigurationError: Association named 'specialClasses' was not found on NormalClass.includes; perhaps you misspelled it?
Should I be doing something else?

Gerbil,
Basically, you need to first set your associations properly.
Look at section 2.4 The has_many :through Association in Rails guides
Once you set it, you can pull up the data you want by pulling the student_id key

Related

achieve habtm on single model in rails

I have a problem with habtm on a single model in rails.
Example:
Let us say i have a User model with two roles "Student" and "teacher". User model is common for two roles. Now
Each student can be associated to many teachers
Each teacher can be associated to many students
In rails notation, their should be habtm between teacher and student
How this can be achieved with single table.
Thanks,
Aashish
It can't be done with a single table. In a many-to-many relationship, no matter what, you always need a table where you store the associations.
In your case, given the association seems to be parent/child, then you just need two tables instead of one.
How to implement it, it depends on your database structure and data organization. You should create an users_users table (as part of the habtm) and configure the references accordingly. If the user table, as it seems to be, is also used for STI, then the configuration may change a little bit.

How to search on joining table in Rails 3 which doesn't have a model?

I have two models merchant and category with a HABM relationship so have a joining table called categories_merchants
How can I write the following query in ActiveRecords?
SELECT
categories_merchants.merchant_id
WHERE
categories_merchants.category_id IN (1,2,3,4)
NOTE: The joining table doesn't have a model, it works automatically in Rails 3 without need for one.
If you want to do such a query you should transform your HABTM in a has_many :trough and create a model for the joining table and query based on that.
Alternatively, but possibly with worse performance, you could do:
Merchant
.select(:id)
.joins("categories_merchants ON categories_merchants.merchant_id = merchant.id")
.where("categories_merchants.category_id IN (?)", [1,2,3,4])

When making model1_model2 tables, do I create a model or?

I have a users table, and a roles table.
I want to make a table like:
model1_model2
with columns:
model1_id
model2_id
other_column int
other_column2 int
Since I need to expose those other columns (other than id's), do I just make a model that matches this table and call it Module1Module2?
It looks like you're looking for the has_and_belongs_to_many relationship.
You shouldn't be putting information in a join table unless it describes the relationship between the two models, in which case has_and_belongs_to_many does not apply and you must make a model specifically for the relation.
Pretty much..
This is an excelent resource with exactly what you're looking for:
http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association

Avoiding Duplicate Data in DB (for use with Rails)

I have five tables that I am trying to get to work nicely together but may need some help.
I have three main tables:
accounts
members
and roles.
With two join tables
account_members
and account_member_roles.
The accounts and members table are joined by account_members (fk account_id and member_id) table.
The other 2 tables are the problem (roles and account_member_roles).
A member of an account can have more than one role and I have the account_member_roles (fk account_member_id and role_id) table joining the account_members join table and the roles table.
That seems logical but can you have a relationship with a join table? What I'd like to be able to do is when creaeting an account, for instance, I would like #account.save to include the roles and update the account_member_roles table neatly ..... but through the account_members join table.
I've tried .....
accept_nested_attributes_for :members, :account_member_roles
in the account.rb but I get .....
ActiveRecord::HasManyThroughCantAssociateThroughHasManyReflection (Cannot modify association 'Account#account_member_roles' because the source reflection class 'AccountMemberRole' is associated to 'AccountMember' via :has_many.)
upon trying to save a record.
Any advice on how I should approach this?
CIA
-ants
If I am reading this correctly you have:
accounts habtm members
members habtm accounts
members has_many roles
If that is accurate you just need a join table between accounts and members and then just a regular FK between members and roles. #account.members and #account.members.roles would both give you access to the attributes you need and #account.save should save the whole mess without a fuss.
I am not sure what compels you to have that account_members_roles table. I don't if Rails can handle that. I know I sure can't. :)
Take a read here:
http://blog.hasmanythrough.com/2006/4/17/join-models-not-proxy-collections
The main difference between a simple
has_and_belongs_to_many join table and
a has_many :through join model is that
the join model can have attributes
other than the foreign keys for the
records it is joining. In fact, if you
didn't have those other attributes you
probably wouldn't use a join model and
would settle for a join table.
So it seems that you want to use has_many :through and you would be set.

Rails ActiveRecord Relationships

How do the relationships magically function when only the models are altered?
If I want a "has__and___belongs___to__many" relationship, what should I name the table (so Rails can use it) that contains the two foreign keys?
Short answer: You can't just tell the models that they're related; there have to be columns in the database for it too.
When you set up related models, Rails assumes you've followed a convention which allows it to find the things you wrote. Here's what happens:
You set up the tables.
Following conventions in Rails, you name the table in a particular, predictable way (a plural noun, e.g. people). In this table, when you have a relationship to another table, you have to create that column and name it in another predictable way (e.g. bank_account_id, if you're relating to the bank_accounts table).
You write a model class inheriting from ActiveRecord::Base
class Person < ActiveRecord::Base
When you instantiate one of these models, the ActiveRecord::Base constructor looks at the name of the class, converts it to lowercase and pluralizes it. Here, by reading Person, it yields people, the name of the table we created earlier. Now ActiveRecord knows where to get all the information about a person, and it can read the SQL output to figure out what the columns are.
You add relationships to the model: has_many, belongs_to or has_one.
When you type something like, has_many :bank_accounts, it assumes a few things:
The name of the model that you relate to is BankAccount (from camel-casing :bank_accounts).
The name of the column in the people table which refers to a bank account is bank_account_id (from singularizing :bank_accounts).
Since the relationship is has_many, ActiveRecord knows to give you methods like john.bank_accounts, using plural names for things.
Putting all of that together, ActiveRecord knows how to make SQL queries that will give you a person's bank accounts. It knows where to find everything, because you followed a naming convention that it understands when you created the table and its colums.
One of the neat things about Ruby is that you can run methods on a whole class, and those methods can add other methods to a class. That's exactly what has_many and friends are doing.
This works because you are following "Convention over Configuration".
If you state that a customer model has many orders then rails expects there to be a customer_id field on the orders table.
If you have followed these conventions then rails will use them and will be able to build the necessary SQL to find all the orders for a given customer.
If you look at the development.log file when you are developing your application you will be able to see the necessary SQL being built to select all orders for a given customer.
Rails does not create tables without you asking it to. The creation of tables is achieved by generating a migration which will create/alter tables for you. The fact that you create a customer model and then state within it that it has_many :orders will not create you an orders table. You will need to do that for yourself within a migration to create an orders table. Within that migration you will need to either add a customer_id column or use the belongs_to: customer statement to get the customer_id field added to the orders table.
The rails guide for this is pretty useful

Resources