I am new to rails and unclear about how to efficiently display breadcrumbs on a multi model tree hierarchy. My app tree is 7 models/levels deep but I will illustrate with 3.
class One
has_many :twos
class Two
belongs_to :one
has_many :threes
class Three
belongs_to :two
For example, say I want breadcrumbs on a show three view (linking to the parent instances of two and one). I am currently using AR associations in the controller:
add breadcrumb #three.two
add breadcrumb #three.two.one
This works fine except two additional SQL queries are run (to retrieve the two and one ancestors).
How can I have breadcrumbs more efficiently?
[Unfortunately, the Ancestry gem only seems to work with one model but is the idea of serialising the breadcrumb into a column worth pursuing? This is such a basic requirement that I suspect I am over complicating this out of ignorance.]
Related
I am building an accommodation booking website on rails and I am confused about one aspect of the models. So normally the way I know of building it is by having a Room model that has many Reservations and the Reservation model belongs to the Room model. Problem is that this time I want the visitor to be able to book multiple rooms on one reservation. Is the Room has many Reservations association correct for that usage? Can anyone help me find a way of building that, do I have to use a single form that makes multiple records? I am sorry for my ignorance, it's the first time a concept like this fall into my hands.
Thank you all very much
You essentially need to have a many-to-many relationship defined and rails has a couple options to do so.
One option is the has_and_belongs_to_many relationship, which you can read up on here. However, my preferred option is the has_many, through: [model] approach as such:
class Room
has_many :room_reservations
has_many :reservations, through: :room_reservations
end
class Reservation
has_many :room_reservations
has_many :rooms, through: :room_reservations
end
class RoomReservation
belongs_to :room
belongs_to :reservation
end
essentially you have an intermediate table to create the many-to-many join.
Given that I have a model that stores movies, what would be the best way to specify relationships such as movie sequels and prequels?
I'd like to access these relationships using simple accessors such as movie.sequels (which would return an ordered list of movies that are sequels to movie) and move.prequels.
I've considered using a has_many :through relationship with a secondary model but how would I maintain movie sequence?
Or could there be a better methodology entirely?
An easy way could be using an ActiveRecord plugin like acts_as_list which allows you to define ordering between different items. You'd need to add a field to use as a scope, such as saga, so the order is defined within movies which belong to the same saga.
https://github.com/swanandp/acts_as_list
The plugin provides handy methods lower_items and higher_items which would work like the sequels and prequels methods you are looking for,
I am currently going through Hartl's Rails Tutorial, and through the first 10 chapters or so have gotten used to the convention of putting most of the actions/methods in the controller. Currently, as the book is going through and defining a feed method for the Microposts, the method is placed with the User.rb model instead. As I am relatively new to the world of rails (and programming in general), I was wondering what the rationale or convention followed for putting this method (copied below) in the Model?
The method placed in the User.rb model:
def feed
# This is preliminary. See "Following users" for the full implementation.
Micropost.where("user_id = ?", id)
end
There is actually quite some contention on what code to put where, but in general, there are some easy guidelines to follow.
Does the method have to know some detail about the underlying data structure? Put it in the model.
An easy way to determine this is when it uses ActiveRecord methods like find, where, or specific columns in the database. By keeping this logic in the model, that means if you need to change the underlying datastore, you only have to change the model.
Does the method have some say in how a page is going to be rendered? Put it in the controller.
Generally, controllers should be pretty thin, pushing data to views and saving form data back to models.
While (if I remember correctly) Hartl does not take about non-rails classes, don't be afraid to put 'business logic' outside of the rails structure. You can create a app/lib or app/services or app/x directory and put plain old ruby objects in there, which can then be called from your controllers and models to handle those things they are good at.
Aim to 'push' things 'up' into the model as much as possible, then they will be repeated less and available to more. Don't just use models for Active Record database tables.
You can often unit test models easier.
Another 'next' place to put stuff that is shared is in /lib
I have a model that for edit/update actions only is logically split into two forms. The model is Venue. I created app/controllers/venues_controller.rb. The two sub-forms are Details and Policies, so I created app/controllers/venues/details_controller.rb and app/controllers/venues/policies_controller.rb, as well as their corresponding views. The child controllers do inherit from VenuesController. I added the venues namespace to my routes, so it now looks like:
resources :venues
namespace :venues do
:details, :policies
end
The routes work correctly, the correct views load, the "edit" action on the sub-controllers is called correctly. However, in the sub-views, I'm using the RESTful form_for(#venue), so when the form is POSTed (PUT) it is going to venue_path, not venue_details_path.
I looked at the docs for form_for and can't figure out a way to keep my sub-forms restful. You can add a token for a namespace a la form_for([:namespace, #model]), but in my case, the model name is the namespace, so it's inverted.
I really don't want to split the model itself, since that has other implications that would be harder to address.
So far, I see two solutions, both of which I don't like:
1. Let both views POST to VenuesController#update and deal with any differences there (more lame controller code)
2. Use form_tag and _tag helpers (more lame view code)
Am I missing something obvious? Is there something different I can do in the routes, or is there another way to call form_for?
I've scanned some posts about Presenter and Conductor patterns but they don't seem to fit this problem. I've read a few stackoverflow threads about whether creating two controllers for one model koscher (it is), but nothing about this specific issue.
Ah, found it. form_for(#venue, :url => venues_detail_path(#venue)). Gotta love Rails.
Suppose i have mapping table map_user_roles. I have defined models Role and User. Both are associated to each other by relationship has_and_belongs_to_many. Of course it does not make sense to define model for mapping table in rails.
I have defined users_controller and roles_controller for crud operations on user and role respectively.
For association of user-role, what should i do? Should i define separate controller like user_roles_controller or should i make modifications in Role and User controller(if so how to do so) ?
Please suggest, what is good practice. Examples and good links would be great help
Thanks for devoting time.
I don't see what a separate controller for the association would offer that couldn't be achieved with your existing UsersController and RolesController. Also, note that sometimes is does make sense to define a model for the mapping table, that's what the has_many :through association is for. You should use it if you need to store extra attributes against the join model.