I am coming from a Java background where we write our own queries or stored procedures and deal directly with low level database stuff.
I am going though AWDR 3rd edition book and can not grasp the joins concept.
Can someone share a resource they used when first coming to Rails?
Let's say I want a Customer table and Order table. a customer can place many orders. So will my Customer Model class contain :has_many order_id
If I do the above, will it make foreign/primary keys in the actual database?
Now let's say I want to find all customers which order with id 5.
How will I do that?
Is it good to just go with find_by_sql?
Take a look at http://guides.rubyonrails.org/association_basics.html
It has a pretty good explanation of Rails Associations, how they work, why you need them, and how to use them.
I think I can give you a quick rundown.
You're used to dealing with SQL directly, and the nice thing is that Rails promotes good database design. If you have a books table and a chapters table, then a book will have many chapters, correct? So just as in other database setups, the chapter table should have a foreign key telling what book it belongs to.
Assuming you have this foreign key in the chapters table, you can setup your Book model like so:
# app/models/book.rb
class Book < ActiveRecord::Base
has_many :chapters
end
You're telling Rails that a book literally has many chapters. So if you have a book object, you can say book.chapters and that will return an array of the chapter objects that belong to this book. Rails will know to look at the chapters table for the book_id foreign key, no custom SQL required.
Conversely, assuming this same database setup, you can define your chapter model to be associated with books, like this:
# app/models/chapter.rb
class Chapter < ActiveRecord::Base
belongs_to :book
end
Notice :book here is singular, just an idiom that helps readability, since a chapter can only belong to a single book. Now if you have a chapter object and say chapter.book, it will return the book object that the chapter belongs to.
Just as in other database applications, the foreign key is always on the "belonged to" table.
I hope this helps!
As suggested the Ruby On Rails Guides is a good place to start, along with the RailsCast site
The key point is that the foreign keys, although implied by the use of the ActiveRecord abstractions such as :belongs_to, :has_many, :has_and_belongs_to_many etc, are not created for you. In the Rails Guides notes on Associations you'll notice comments like:
"In any case, Rails will not create foreign key columns for you. You need to explicitly define them as part of your migrations."
This note is often referenced in the details of the individual associations under the :foreign_key option.
I guess it's often not obvious and from my experience (esp. coming from a Java/C++ background) I found that I had to print out and read the set of guides a couple of times to really appreciate the elegance, simplicity as well as the wealth of information contained within them.
On a side note - it's great not to have to deal with all the low level plumbing as per the Java experience.
Related
It is my first question, but I have yet to find an answer, so I hope it doesn't violate any rule.
I have a problem with a seemingly simple rails issue. I have taken the time to read about relationship models in rails (has_many :through) and came upon this example:
Exemplary model relations
In my model, I have Anthology (phyisicians), Poem(patients), and an anthology_poem relationship model (appointments). In may relationship table, I have a column, order, that indicates the position of a specific poem in a specific anthology.
The question is - How do I address said "order" column? How do I update it/read it? I imagine something like:
book.poems.first.order
which obviously doesn't work.
I'd like to be able to do it without too much hacking, because I fell in love with how simply rails handled the rest of the stuff.
Thanks in advance!
If you want to access your relationship model attribute you should call it on that model:
Appointment.where(physician: physician).pluck(:order)
I try to do for me a kind of application for a Writer. Possibility to add chapters, scenes, characters and anecdotes.
My models : chapter, scene, character, anecdote
Chapter has a number, a title, and has scenes and anecdotes
Anedote has a subject and one or several themes
Scene has a text, one or several characters, a place, a period
Character can appear in on or several scenes
I did the tutorial on Ruby on Rails by Michael Hartl, but I have some difficulties now to implement my model.
Do you know some tutorials on database associations like I want to do, or explanations ?
I hope you understand, and sorry for my bad english
Thanks
You can't do Scene has_many: characters and Charaker has_many: scenes. `has_many expects to find a foreign key on associated model and such a key can only point to one parent.
What you need is either:
has_and_belongs_to_many association
has_many :through association
Those associations are rather a vast subject to describe in a single question. Please have some reading: http://guides.rubyonrails.org/association_basics.html. I strongly recommend reading at least first three chapters and scan the forth before starting designing your models. It is really a pain to realize you have designed extra elaborate database structure which could have been achieved with AR feature you didn't know at the time.
I have HABTM relationships between Topic and Chapter Now I want to display chapters in a specific order under topics.
For Eg: A particular chapter might be 2nd chapter under one topic, and might be 8th chapter under another topic.
How Should I do it? Thanks in advance.
In this case you have a non-trivial many-to-many relationship, the join table needs to contain more than just foreign keys to each of main tables.
As a result, you'll want to move from HABTM to has_many :through on both Topic and Chapter, and change the join table to be its own model that not only relates the two main tables to each other, but also stores the order in a column (which, by the way, you should not name "order", since it will confuse SQL and Rails :-).
Converting from a standard Rails HABTM model is pretty easy, but one bit of advice: think of what it is that makes what used to be just a join table a real model ... and use that as a name for the new model (and associated new table). In a simple HABTM, you would create a table chapters_topics, when it becomes a model it might be "ChapterTopic" (resulting in a table chapter_topics).
I have a Post model and I would like to create a Tag model so that posts can have tags (more than one at a time). I want to be able to search a post's tags and search posts tagged as X.
This is what I've realized so far in order to make this work (correct me if I'm wrong):
The Tag model only needs a :name attribute and the Post model needs a :tag_list attribute)
The Post and Tag must have either has_and_belongs_to_many or many-to-many associations between them (not sure which one).
I have no idea about the view or the form or how separating tags with a coma or a space will tun into separate tags that belong to the post.
Any suggestions or insights (with examples if possible).
A few recommendations:
I think you'll need a join table as well, something like posts_tags or posts_to_tags, that
has a tag_id and a post_id.
There's a pretty good example of the difference between many-to-many and HABTM in the AR docs. In this case, I'd use the HABTM because your join table doesn't have any meaningful characteristics (unlike the example, where "Assignment" is a first-class model).
Going from comma-delimited string to separate tags should probably be done with a before_save filter or something -- not sure there's built-in behavior here.
You could also look into the tagging gems listed on Ruby Toolbox if you're not doing this for learning purposes.
You can use has_many :through association. This is one of the best solution to your situation.
There is a detailed tutorial on Rails Guide:
http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association
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