Rails 3 Attaching Model ID to every link - ruby-on-rails

My application centers around an event and specifically the event's ID. Whenever a user navigates to different sections (controllers) of the site, I need to be able to carry the event's ID with it.
I'm guessing including the event's ID in the URL is the preferred method in case a user opens multiple browser windows.
I don't want to manually append the event's ID to every link. Is there a helper method I could create to do this for me?
Thanks

You need to create a nested resource in your routes file, this will add something like "/event/#eventid" to the beginning of your path. You can then access this from your controllers with params[:event_id]
eg:
routes.rb
resources :events do
# Other controllers routes go here
end
controller_whatever.rb
def index
#whatever = Event.find(params[:event_id]).whatever.all
end
...
Obviously it would be best to use a before filter, but you get the idea.

You should store that in session data:
session[:event_id] = event_id
You will then be able to access that throughout the user's session.
UPDATE:
You may want to have a look at nested resources.

I recommend to use thomasfedb's solution. If it isn't possible for any reason you could do it by overwriting the url_for method like in this question

Related

How to create a custom route for show action in rails 5?

I have a model 'Item'. It all works fine, however am not completely satisfied with its show path. I want to use certain parameters from items table to construct a more SEO friendly url. So here is my question..
How can I change my Show action url
from
'mysite.com/items/1'
to
'mysite.com/items/item-name/item-city/item-id' where item-name, item-city, and item-id are dynamic for each specific item.
Is it possible to achieve this without a gem? if yes, how? If no, which gem would you suggest to achieve this in simplest way?
Thanks
One approach to this problem is to use route globbing:
http://guides.rubyonrails.org/routing.html#route-globbing-and-wildcard-segments
You should be able to do something like this:
get 'items/*names/:id', to: 'items#show', as: :item_names_path
And put whatever you want in *names. This would take a little experimentation to get it right. I might add a method to item to create the names array.
def names
[city.name, name].uniq.compact
end
Then I believe you would call item_names_path(#item.names, #item)
You can do something relatively simple and stays true to Rails by adding a to_param method to your model like so:
def to_param
"#{id}-#{name}-#{city.name}"
end
What this does is every time you use a method like the item_path, it will use the #item.to_param method (this is what it does now, and returns :id). Generating the normal route, but replacing the :id param with the SEO friendly one.
And, on the other end, when you go to find(params[:id]) in the controller in your show, edit, delete, or update actions, it will to a to_i on it and turn it back into an id. This is what it does now, but to_i on an int is still an int.
Your urls will look something like
/items/56-boston-itemname
The other benefit to this, if you happen to change the item name or the city name, it will change all the urls appropriately, but old urls that were sent in email will still work.

Rails: Why does create/update action point to the same URL like the index action?

When creating or updating a resource, the target URL by default is the same like the index route, for users e.g. localhost:3000/users.
The difference is that instead of POST, PUT method is used (as far as I know).
I find this suboptimal. For example, when having a navigation menu with an item "Create user" in it, I want to set the active CSS class when the item is active. I do this by comparing current_page? to the menu item's URL (e.g. users/new). This works fine, but only when I don't have validation errors. In this case, the URL now isn't users/new anymore, but users.
Is there a good reason why Rails doesn't point to users/new (or users/edit) respectively for POST/PUT requests? Are there any downsides to using them? Is there an easy way to change this behaviour?
The reason is REST.
In a nutshell, Rails treats everything as a resource, and there are conventions followed in order to do so. In a typical CRUD application, you have the Create (POST), Read (GET), Update (PUT/PATCH), and Destroy (DELETE) actions, which are the verbs used to act on resources.
Let's say you have a User resource. A list of users would be found at /users. An individual user, being an individual object of a resource, would then be found at /users/1, where "1" is the identifier of the resource in question.
Now, based on the CRUD verbs available to you, if you wanted to edit a user, what ACTION makes the most sense given the CRUD verbs we talked about? PUT /users/1 is the correct answer; you're updating (the U in CRUD) a particular resource. If you wanted to delete that user? DELETE /users/1 makes sense. If you want to create one? CREATE /users is the logical choice, because you're not acting on a particular object, but on the resource as a whole, similar to GET /users not acting on an individual object, but a collection.
/users/new is a path to a page that will let you do that, but it doesn't mean it should make the CREATE request to /users/new, because "new" doesn't describe a resource the same way.

Overriding the default route / path helper in rails to use something other than the `id` field

I can view any User' object's show page in my app using the url
/users/:id
# eg. /users/7
Instead of using the id from my database, I wanted to use a unique hash id that I generate for each user. It looks neater and avoids exposing my sequential DB information
/users/kF87sl8H2
However I lose the convenience of using the route path helper I was previously using - user_path(#user). I now have to replace it in multiple places with user_path(id: #user.hash_id)
Is there a way to keep the old route helper and just pass it my #user instance? I assume it involves overriding the path helper somehow?
Also, marginally related - is there a best practice around generating those hash ID's? I was just going to use SecureRandom.hex, but I know Google+ uses numbers only and Youtube uses different case letters
e.g. https://www.youtube.com/watch?v=dQw4w9WgXcQ
Is there a good way to generate those?
Thanks!
I believe you can do the following to override the route helper method for your User class
class User
def to_param
hash_id
end
end
Try this.
resources :users, param: :hash_id
add the param to your routes file with resources as above with your model field and change the find method in your controller as below.
#user = User.find_by(hash_id: params[:hash_id])
Here is the officail documentation for the same.

Rails 4 new form defaults from params

I am using form_for in the _form.html.erb view in order to create my form for both the edit and new actions, as per a standard scaffold.
I have a model Owner which has_many pets.
I would like to put an html link on my views/owners/show.html.erb to create a new pet for said owner. This link will point to the new action of pets_controller.rb which when accessed will render the view in pets/new.html.erb
What I want to happen is for the the owner_id to be passed with the link in the url to the new action of pets_controller.rb and then be used as the default for a collection_select in pets/new.html.erb
So I have a link to create a new pet but because that link was on a specific owner page, I want the form to create a new pet to have that owner already set, so the user does not have to select from the list.
This has to be done without changing the behaviour of the edit action/view in pets.
I know that I can pass GET arguments then access them in the controller via params, then create variables in the action which are passed to the view. I can then manually check for a default and set it in the view. I do not need assistance in coding if this is the only solution.
Is there is a better way to do this? A format with which I can pass the params such that the view will just pick them up? Without manually editing my controllers and views?
While my personal inclination would be to do as you said and pass a parameter in the link helper and then access the params array in the pets view, you may find that this is the perfect opportunity to explore Nested Resources. Essentially, you could declare owners/:owner_id/pets/:pet_id route with:
resources :owners do
resources :pets
end
You could then link to this route, and reference :owner_id without having to append the query string to the URI (making somewhat cleaner for reuse).
This is likely more work for you, but also potentially more extensible (and certainly more inline with the Rails way of doing things).
REVISION
Added the following regarding link helpers to the comments, but wanted to reflect it in the answer as well.
To show a pet should be:
<%= link_to owner_pet_path( owner_variable, pet_variable) %>
To view pets' index index should be:
<%= link_to owner_pet_path( owner_variable ) %>
The answer given to this question is fantastic.
As #ConnorCMcKee suggests it would be wise to consider nesting your routes. However, if you are a beginner as myself I found that it helped my learning to simply nest my second controller into the first (i.e. nest PetsController into OwnersController) as a first step. Then afterwards I would continue with the routes.
The method would be something like:
1./ In owners/index.html.erb:
Links to PetsController index action
The key to make this work is to send the :owner_id in your link parameters. Then that Pets index action will have access to that :owner_id and know which :owner_id called it.
2./ In PetsController you would then be able to find that Owner using that id, like so:
params[:owner_id]
Then your actions can start to take advantage of knowing what Owner called them. Remember though that all your redirects inside your PetsController need to preserve params[:owner_id]. That is because once you are inside that nested structure you have to maintain it and stay inside it and always know which :owner_id you are working with.

Routes question: what if I want both a resource to be nested and on its own?

Objective:
Be able to nest a resource, like records inside of users so that I can access /users/1/records to see all of the first users records. But I would also like to see /records to see all of the records ( or the new ones, or something like that ).
Problem
So I know I am missing something somewhere because that cannot be the way to do it. I know I can have like a static page or some other route for that, but I don't think that is very rails-y.
I would have users, so a user would see their page with their records, but also be able to browse records, so I assumed I would need a more general route for that.
Question
What is the appropriate way to browse a nested resource?
PS I have looked at things like this question, which almost address the problem, but deals with a static landing page for non logged in users, this is not what I am looking for.
Not sure how to handle this route later in controllers (never tried), but something like this should work:
resources :records
resources :users do
resources :records
end
I think you'll need to do something in records's index controller to check if its called for some user or not.
UPD: Ok, checked it. Check for params[:user_id] in your index controller.

Resources