custom action for a nested resource without adding to routes - ruby-on-rails

This is probably really simple but I have a nested resource lets say:
map. resources :book, :has_many => :pages
I write an action called "turn" that increases page.count by 1. How do I call this action using a link_to? Thanks a lot in advance.

It's hard to tell where your page.count comes in. In Railish, you would find pages.count (note the 's'). Further, count (and also size) is a read-only attribute on arrays and hashes et.al. provided by ruby that returns the number of elements. You don't set count.
Next, I'm not sure where your turn action is supposed to live, on the Book or the Page? And what is supposed to happen after it does what it does? Finally, a route is what makes an action an action -- without it, it's just a function.
For a moment, we'll assume you are trying to store the number of times a Page in a Book has been visited. It would be a better idea to have an instance variable called reads or times_viewed etc. in your Page model. Assuming your Book model is using restful routing, in Book's show action, you create an instance variable of the Page model being viewed and increment its reads attribute before rendering the view.
If you are trying to make a link sort of how 'Like' works in Facebook, meaning you want to update a record in a table without sending the user to a different page, you'll need to use link_to_remote* and some javascript. In that case, I'd just refer you to the Railscasts on that subject.
*I think as of Rails 3, link_to_remote became just link_to with :remote => true.

Related

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.

link_to 'new' action in a different controller?

I want to have a link at the bottom of my show.html.erb that links to the new action in a different controller.
class Sample < ActiveRecord::Base
belongs_to :song
end
class Song < ActiveRecord::Base
has_many :samples
end
So, at the bottom of the show action for songs, I want to link to new for samples. This seems pretty easy, but I'm struggling to figure this out. I would also like to pass the id from the song to the form as :song_id
Fiddy, because you're new, let me explain how this works...
Routes
Your problem is that you don't understand the Rails routing structure - I'll hopefully explain it for you.
Rails, since it's an MVC framework, builds a series of "routes" for you. These "routes" are stored in the file available at config/routes.rb.
Routes, as described by the Rails documentation are as follows:
The Rails router recognizes URLs and dispatches them to a controller's
action. It can also generate paths and URLs, avoiding the need to
hardcode strings in your views.
The most important thing you should consider here is the way the routes generate paths for you. These paths are simply Rails "helper" methods, which you can call from your views. The reason these exist is two-fold -
They provide you with a DRY (don't repeat yourself) way of accessing / manipulating data
They are constructed around objects, helping maintain the object-orientated nature of Rails
These will likely mean nothing to you. However, what you need to realize that if set up your routes correctly, it seriously helps your app's infrastructure immensely.
--
Rails
This leads us quite nicely onto appreciating the way in which Rails works
Rails is an MVC (model view controller) framework. This might seem somewhat trivial, but in reality, it's one of the most important aspects to learn about Rails development, and here's why:
The Rails software system works by taking "requests" (user input) and then routing them to specific controller#actions. Those controllers then build model data from the database, and will translate that into either variables or objects, which you can use in your view.
The reason I mention this is that this type of development takes a lot of getting used-to, in that your program's flow is not about logic / functionality, but the accessibility of data. Therefore, when you ask about the routes or other parts of your app, you need to firstly remember what data you wish to show, and also how you want that data to be shown - this will give you the ability to construct & use the routes / controller actions which will get it to work properly
--
Fix
In terms of what you're saying, the way you'd go about achieving the result you want will be to use a nested route:
#config/routes.rb
resources :songs do
resources :samples #-> domain.com/songs/:song_id/samples/new
end
This will create a new route for you (which you can check by firing rake routes in your rails c (console). This will give you a path to use for your samples#new action:
#app/views/songs/show.html.erb
<%= link_to #song.name, new_song_sample_path(#song) %>
The above link will take you to the samples#show action, which you'll be able to populate with as much data as you require from the samples controller. The important thing to note is this action will have params[:song_id] available for you to either build an object from, or otherwise
<%= link_to "New Sample", new_sample_path(:song_id => #song_id) %>
Where #song_id is the variable that has that id in it.
Set paths in link_to tag which you can get by running rake_routes in terminal.
Ex
link_to "New song", new_sample_path(#song)
In the example given above #song is the instance variable of your current page.
You can also get some idea from here:
link_to Base URL Randomly Changed
Song Model:
accepts_nested_attributes_for :sample, allow_destroy: true
Route:
resources :songs do
resources :samples
end
Song's Show file:
<%= link_to "New Sample", new_song_sample_path(#song) %>
in url it will be:
/songs/:song_id/sample/new
Try this and let me know it works or not... I hope this helps you

Use multiple checkboxes to change one field - rails controller change params

I've got articles that can be shown in lots of different sites. They can either be visible or not.
I've ended up going for a single bitmasked permission field in the article, rather than lots of has_many permissions separate records.
I'm not sure how best to set this field. What I've done so far is write two methods in the article model - one gives you a hash of {1 => 'true', 2 => 'true', 3 => 'false'} - visible or not on site 1, 2, 3. The second method takes a similar hash and sets the permission field correctly.
I can send the permission hash to my view through the controller, and I can make checkboxes that show if the article is visible or not. These appear on a pop up dialog using jquery. I haven't done it yet, but I think I can use javascript to make a hash to send back.
But I don't know how to make the update controller take the hash from the params, send it to my make permission method and then put that into the params again to update my article.
How would I go about doing this? Or am I barking up the wrong tree entirely.
Any ideas?
I would suggest you to create a Site model which reproduces the different sites. This is especially a good thing if there might come up more websites! Then you could build a has_and_belongs_to_many association between the Site and the Article model to commit on which site an article should be displayed!

Routing via non-database models

We have a structure where we want to view and edit records, filtered by day. But we want the day to be part of the url
/time_records/day
This view shows time_records for a particular day. But when we add a time_record, it needs to redirect back to the same page.
However, it invokes time_records without the "day" part in order to call create. In order to redirect back to the same page, I think I have to pass a model object to redirect_to, but that model would have to be the day itself.
Is the only solution to add a Day object to my model? This seems a bit of a waste as a DateTime is sufficient already logically, this is just about routing.
With:
match '/time_records(/:day)' => 'time_records#show', as: 'time_records'
in routes.rb you can use the url helper method:
time_records_path(day: Date.today)
to generate "/time_records/2011-01-21". This works in part because in Rails, Date objects respond to the to_param method.
This all assumes you're using ruby 1.9.x and rails 3.0.x

Making a single create form using Single Table Inheritance in Rails

I'm using STI in Rails, and I've got a Vehicle object, that has many different types of subclasses, like Car, Truck, etc. It's for a simple app, so STI works fine in this case, but I'm having trouble creating a single form where any type of Vehicle record can be created.
Using the following routing:
resources :vehicles
resources :cars, :controller => 'vehicles'
resources :trucks, :controller => 'vehicles'
I can have /cars and /trucks routing set up, and both pointing to the same form. However, since the form is pointing to the vehicles controller, and generating a Vehicle object for the form, it has no way to know that the /cars url should create a Car object.
I'm trying to get a routing system set up where /cars would point to a form that would intrinsically know to make a object for the form using either Car.new or even Report.new(:type => "Car"). I thought about working a routing system like /vehicles/:subclass, and somehow using params[:subclass] in the controller, but I also can't figure out how to do that sort of routing and still avoid other routing errors caused by Rails' STI magic.
I could always parse the URL to get the value, but that seems like an unsafe and hacky way to go about it.
I'm curious if anyone has any advice or experience on the Rails way to do this. Thanks!
Since you want to use the same form for all vehicles, then I'm assuming all the fields are the same except for the object type. Then why not have a combo box in the form to allow the user select what type of object the user want to create?
You can then handle the proper object persistent in the create action in the controller.

Resources