Polymorphic urls with singular resources - ruby

I'm getting strange output when using the following routing setup:
resources :warranty_types do
resources :decisions
end
resource :warranty_review, :only => [] do
resources :decisions
end
I have many warranty_types but only one warranty_review (thus the singular route declaration). The decisions are polymorphically associated with both. I have just a single decisions controller and a single _form.html.haml partial to render the form for a decision.
This is the view code:
= simple_form_for #decision, :url => [#decision_tree_owner, #decision.becomes(Decision)] do |form|
The warranty_type url looks like this (for a new decision):
/warranty_types/2/decisions
whereas the warranty_review url looks like this:
/admin/warranty_review/decisions.1
I think because the warranty_review id has no where to go, it's just getting appended to the end as an extension.
Can someone explain what's going on here and how I might be able to fix it?
I can work around it by trying to detect for a warranty_review class and substituting #decision_tree_owner with :warranty_review and this generates the correct url, but this is messy. I would have thought that the routing would be smart enough to realise that warranty_review is a singular resource and thus discard the id from the URL.
This is Rails 3 by the way :)

Apparently it's a long standing rails bug where polymorphic_url has no way of knowing whether a resource is singular or not from the routes setup:
https://rails.lighthouseapp.com/projects/8994/tickets/4077-wrong-redirect-after-creation-of-nested-singleton-resource-using-responder
I'm just going to resort to using a non-singular route even though there will only ever be one warranty_review. It's just aesthetics at the end of the day.

Related

Fire an action when a link gets clicked to a page that has the same action (VoltRb)

At http://localhost:3000/books, I have an index page where I have a list of books.
When you click on one of the links, the action to which it is bound, book, gets fired:
However, when you click on one of the links from one of the book pages, the book action doesn't get fired:
Note that the URL does change when the links are clicked, from both the index page and the book pages, but the problem that I'm having is that book doesn't get activated when you click on a link to a book page from another book page. How can I fix a situation like this?
FYI, here is a repo where this problem can be reproduced.
The method book doesn't get called twice because your view is already setup. The change in the url only triggers an reactive update in your view.
What is it that you are trying to achieve?
As it turns out, Volt computations are a way to solve this problem. By using the params collection, you can attach computations to changes in the URL. I solved this issue and got book to run on changes in the URL like so: https://github.com/ylluminarious/volt_action_problems/commit/5fcefc16d7b14a980f68ce572a80f25540d21636.
Sorry for the late reply. This is a known issue thats on my to fix list. As GDP2 mentioned, you can use .watch! to handle it, or the probably better way to do it is to write your controllers in a more functional way so that the data being pulled from params is used in methods instead of setting instance variables.
So for example, if your using the params in a query, instead of doing something like:
attr_reader :query
def index
#item = store.items.where(name: params._name).first
end
You could do something like:
def query
store.items.where(name: params._name).first
end
This might seem less efficient, but there's a lot of caching and this is pretty much just as efficient.
Once I get time though, I'll make it retrigger the action method when accessed data changes. (Sorry, just haven't gotten to it.)

Understanding routing in rails

Ok first off I have to say I'm very new to Rails. I have spent the last few days going through tutorial after tutorial and still missing a few concepts. Mainly because I just want to start off with a simple site structure but every tutorial is either a shopping cart or a blog which are more applications within a site. I have some pages on my site that will have photo galleries that are database driven but for now I'm just trying to get some answers to these questions.
Site structure:
home | photos | about | work | contact
Work has sub pages for example:
html | ruby | rails | bla-bla
Controllers:
Do I need to set up a controller for every new page or could I have one controller that handles all main level pages.
If I could use one controller how would that work and would I need to define an action to handle each page ( view ) like
class MainController < ApplicationController
def index
end
def photos
end
def contact
end
# and so on ......
end
Routing:
How would I route the above.
Whats the difference between a resource and a *get
get "photos/photos"
resources :photos
When I setup a controller for a specific page like.
rails g controller Contact contact
It creates a folder inside my views called contact and inside it is a view called contact meaning my url is contact/contact
it also adds a route get "contact/contact"
Now what if I only want the user to type http://mydomain/contact then this is not going to work. How would I set it up so the user doesn't have to add http://mydomain/contact/contact
The only way I could find a way around this was to use the match verb.
match "contact" => 'contact#contact'
Does this mean I have to use the match for every page on my site to change the url path?
These are just a few of many question I have that are not so clear in most of the tutorials I have gone over. Please don't tell me to use the user guide as I have already and am felling overwhelmed right now. I just would love some clear answers from some developers who are working in rails and would go about setting up a structure like I have outlined above.
Thanks
You're going to get some conflicting advice I think, but here's what I'd do.
Create a MainController (I prefer HomeController as it will also handle the homepage, but that's just me). This controller will handle the actions for home, about, and contact.
Create a PhotosController since you said photos come from the database and there's a good chance there is an index/listing page and individual pages for each photo.
Create a WorksController that handles the work main page and all the sub pages.
Now.. some people would argue (myself included) that home, about, contact, and all the work pages (sub pages too) should be handled by a generic PagesController that is smart enough to know what to do. I'm not gonna get into that now though.
The difference between these two routes:
get "photos/photos"
resources :photos
Is that the first will only create a single route for a GET request to '/photos/photos'. The second will create the standard CRUD operations for '/photos'.
For your static pages, I probably would go ahead and just create:
match "about" => 'main#about'
match "contact" => 'main#contact'
...
It's harder to say for the photos and work since I don't know what all you'll be doing there. The above isn't as DRY as it could be, but unless you go the "smart pages controller" route it's the simplest.

What is The Rails Way for requesting an alternate view of all records?

I have a rails app that has a list of Products, and therefore I have an index action on my ProductsController that allows me to see a list of them all.
I want to have another view of the products that presents them with a lot more information and in a different format -- what's The Rails Way for doing that?
I figure my main options are:
pass a parameter (products/index.html?other_view=true) and then have an if else block in ProductsController#index that renders a different view as required. That feels a bit messy.
pass a parameter (products/index.html?other_view=true) and then have an if else block in my view (index.html.haml) that renders different html as required. (I already know this is not the right choice.)
Implement a new action on my controller (e.g.: ProductsController#detailed_index) that has it's own view (detailed_index.html.haml). Is that no longer RESTful?
Is one of those preferable, or is there another option I haven't considered?
Thanks!
Another way of doing it would be via a custom format. This is commonly done to provide mobile specific versions of pages, but I don't see why the same idea couldn't be applied here.
Register :detailed as an alias of text/html and then have index.detailed.haml (or .erb) with the extra information. If you need to load extra data for the detailed view you can do so within the respond_to block.
Then visitors to /somecollection/index.detailed should see the detailed view. You can link to it with some_collection_path(:format=>'detailed')
I'm not sure whether this is 'bettrr' than the alternatives but there is a certain logic I think to saying that a detailed view is just an alternative representation of the data, which is what formats are for.
After doing some reading, I think that adding a new RESTful action (option #3 in my question) is the way to go. Details are here: http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
I've updated my routes.rb like this:
resources :products do
get 'detailed', :on => :collection
end
And added a corresponding action to my ProductsController:
def detailed
# full_details is a scope that eager-loads all the associations
respond_with Product.full_details
end
And then of course added a detailed.html.haml view that shows the products in a the detailed way I wanted. I can link to this with detailed_products_path which generates the URL /products/detailed.
After implementing this I'm sure this was the right way to go. As the RoR guides say, if I was doing a lot of custom actions it probably means I should have another controller, but just one extra action like this is easy to implement, is DRY and works well. It feels like The Rails Way. :-)

Trouble passing value from view to controller in Rails 3.1.1

I have two model Product and Category, they have has_many, and belongs_to association respectively. Now, what I am trying to do is when I click on particular category I want all the products of that category to be listed. How do I do that
here is my view
<p><%=link_to #product.category.name, show_by_category_products_path(#product.category.id)%> <%= #product.name%> <%=#product.category.id%><p>
and method in controller
def show_by_category
#products = Product.where("category_id=?", :id)
end
Thanks! (I know its simple stuff, but sometimes you get blind and can't see a straightforward way so you have to sought help of others)
EDIT
okay maybe I figured out a way to go around this.. but I am not sure if it is done in right way
Now my view and model looks something like this
<p><%=link_to #product.category.name, show_by_category_product_path(id: #product.id)%> <%= #product.name%>
def show_by_category
#prod = Product.find(params[:id])
#products = Product.where('category_id=?', #prod.category_id)
end
Tell me if this is right way?
Your find should look more like Category.find(params[:id]).products. But try to follow RESTful routing principles, and nest your resources. Rails will do much more for you.
I would recommend you to read at least Getting Started guide, because you are doing it wrong.

Route question regarding Authlogic and Rails 3.0.0

I upgraded an app I am working on from Rails 3.0.0.beta4 to Rails 3.0.0 and hit an unexpected error. I'm using authlogic for authentication, and after the upgrade the route for new user session form started throwing this error.
undefined method `user_sessions_path'
Ok, I'm using a singular controller name. Not sure what is different between beta4 and the new release that caused the problem.
In my routes.rb file I have this:
get "user_session/new", :as => :login
get "user_session/destroy", :as => :logout
resources :user_session, :controller => :user_session
Which defines my singular controller routes.
To fix the problem I had to change the first line of the form from this:
<%= form_for #user_session do |f| %>
to this:
<%= form_for #user_session, :url => user_session_index_path do |f| %>
What is striking me as weird is the name of the route. Running rake routes revealed the name of the route, but I don't understand why the index was needed. I was expecting something more like user_session_path for the post method. My user_session routes are the only ones acting this way. All of the other are as I expect.
Heres the output from rake routes:
user_session_index GET /user_session(.:format) {:action=>"index", :controller=>"user_session"}
user_session_index POST /user_session(.:format) {:action=>"create", :controller=>"user_session"}
This works, but I'm curious to know if anyone else has encountered this.
First of all, I don't understand, why do you specify the controller name, when it is the same as the resources name? Those two, are equivalent:
resources :user_session, :controller => :user_session
resources :user_session
AFAIR by design create just does POST onto the same path as index. By definition, when controller name is singular, router won't be able to create a plural version of the name. It works the other way around. Thus, theres a _index suffix in both index and create actions.
Singular name would suggest, that the resource is singular, so you should just use (sigular for resource):
resource :user_session
In this case there will be no index action (as it makes no sence for singular resource), and the name for create path will be user_session_path.
As a side note, singular resource doesn't imply, that there is only one instance of the model. It just specifies how do you access the resource. For example you can have multiple users with profiles, but there is perfect sense to use singular resource in order to manage the profiles, since each use can only access his own profile.
ps. I moved on to Devise for authentication before Rails 3 and I don't quite remember how routes used to be solved in Authlogic.

Resources