kakubei
kakubei

Reputation: 5400

Rails redirect with new action

very new to rails. I've been following a book which helps a lot, but this I can't figure out:

I have a controller Techniques with some actions (methods) in it:

def patadas
    @technique = Category.find(4).technique
end

def golpes
    @technique = Category.find(3).technique
    respond_to do |format|      
        format.html { redirect_to(patadas_path) } 
    end
end

The idea is to have a single page where I can send different techniques to and it will render them. The patadas.html.erb page has this in it:

[ some html ]

<% if @technique then %>
        <% @technique.each do |p| %>
            (<%= p.order %>) <%= p.korean %> - <%= p.spanish %><br />
        <% end %>
    <% else %>
        No techniques specified to show!    
    <% end %>

My problem is with the redirect. I want to be able to send different methods to that same page (obviously I'd have to rename it to techniques or something other than patadas) and have it render the technique that corresponds to the method called. Right now the redirect gets executed, but it shows the patadas method always.

Oh, I have this in the routes.rb file:

match '/patadas' => 'techniques#patadas', :as => 'patadas'
match '/golpes' => 'techniques#golpes', :as => 'golpes'

All the tutorials and books, etc I've seen explain how to do it for one view for each action, but this is really wasteful, I want one view for all these different actions. With the above routes I understand that if I build another view called 'golpes.html.erb' it would render them, but I'm looking for a single view with different actions.

Thanks.

PS Also, is it possible to have something like this:

@frontal.each { |p| puts "(#{p.order}) #{p.korean} = #{p.spanish}" }

in a view (html.erb) file? It's much more elegant than the above craziness of opening and closing <%= %> tags. With the beauty of Ruby, it seems wasteful to use such a syntax. I'm sure there must be but I haven't gotten that advanced yet :)

Edit: In view of all the changes I've made (created a scaffolding for the Category), I'm rewriting the question to make things clearer. So now this is what I have:

categories_controller.rb

[ bunch of stuff ]

def show
    @category = Category.find(params[:id])
  end

routes.rb

resources :categories

In the show file I'd like to list all categories by id so the /categories/show.html.erb file:

I want to get category.order, category.category, category.spanish to show here
<%= link_to 'Edit', edit_category_path(@category) %> |
<%= link_to 'Back', categories_path %>

Please excuse my idiocy, but I can't figure out what to put in this file to list the content. If I try to do something like:

<% @category.each do |cat| %>
    <li><%= cat.category %> - <%= cat.spanish %></li>           
<% end %>

I get an error

undefined method `each' for #<Category:0x007f81c42a3fd0>

(The original question had to do with routes, I wrongly wanted routes to handle different actions, something that is actually done with the show template, hence jimworm's answer. I edited the question for clarity since I changed so many things, but can't really remember the original phrasing, sorry)

Upvotes: 1

Views: 1051

Answers (1)

jimworm
jimworm

Reputation: 2741

Welcome to the Rails way, please ask more if you're still stuck.

Redirects are redirects, no information is preserved between requests. Looks like you're trying to list techniques for each category? Keep in mind that the only input you have is a category, not anything to do with techniques. I'd recommend a nested route in this case.

# config/routes.rb
# this gives you the route /categories/:category_id/techniques, among other things
resources :categories do
  member do
    resources :techniques
  end
end

# app/controllers/techniques_controller.rb
# note that this is only called from inside the nested route
# so params[:category_id] is available
class TechniquesController < ActionController::Base
  def index
    @category = Category.find params[:category_id]
    @techniques = @category.techniques
  end
end

# app/views/techniques/show.html.erb
<% @techniques.each do |technique| %>
  <p>(<%= technique.order -%>) <%= technique.korean -%> - <%= technique.spanish -%></p>
<% end %>

Note the usage of params[:category_id] instead of fixed route names. You could always use friendly_id to find categories by a slug instead of an integer.

https://github.com/norman/friendly_id

Edit: Addressing your comment one point at a time (but not in the right order):

In Rails convention, there's a big difference between technique and techniques. A seasoned Rubyist would never name a list of techniques technique, because that's just confusing! An instance of Technique must be a technique, so to speak, and if there's more than one technique in each instance of that model, you'd call it TechniqueList or TechniqueGroup or something.

What you're asking for is to have a list of techniques displayed on a category's show action. In that case, you won't need the nested route. You could use the same method to show a list of categories for a particular technique (provided that you have a many-to-many relationship between categories and techniques).

# app/controllers/categories_controller.rb
class CategoriesController < ActionController::Base
  def show
    # `includes` joins the techniques table, avoids n+1 lookups
    @category = Category.includes(:techniques).find params[:id]
  end
end

# app/views/categories/show.html.erb
<% @category.techniques.each do |technique| %>
  <p>(<%= technique.order -%>) <%= technique.korean -%> - <%= technique.spanish -%></p>
<% end %>

Sub-categories: what are they? A model? A query on the Category model? I'm going to treat it like a query in the code below.

# app/models/category.rb
class Category < ActiveRecord::Base
  class << self # this adds class methods
    def sub_category_query(param)
      # this line is an example only, it depends on your query
      where(:sub_category => param)
    end
  end
end

# app/controllers/categories_controller.rb
class CategoriesController < ActionController::Base
  def sub_category
    @categories = Category.sub_category_query params[:sub_category]
    # since it's just showing a list of categories
    # you can probably reuse the index template here
    render :index
  end
end

# config/routes.rb
resources :categories do
  collection do
    # this give you an extra route to search by sub-category
    # rails guesses the action name, and expects a param here
    get 'sub_category/:sub_category'
  end
end

Upvotes: 1

Related Questions