6

I have about 5 models that behave very similarly. In fact, I'd like them to share an action for displaying them. For example, for models Car, Truck, Van I want to have a definition like:

[Car, Truck, Van].each do |Model|
  action_for Model do #I made this up to show what I mean
    def index
      @model = Model.all
      @model_names = @model.map(&:name).join(', ')
    end
  end
end

How would I do this so I'm not defining the same action in multiple controllers? (Which isn't very DRY) Would it be in the application_controller? And if it's not too much to ask, how could I do this so they also share the view?

UPDATE

It would be preferred if this can be outside the individual controllers. If I can get this to work right, I'd like to not even have to generate the individual controllers.

Kyle Macey
  • 8,074
  • 2
  • 38
  • 78
  • You might be interested in peeping or using [Inheritable Resources](https://github.com/josevalim/inherited_resources) by José Valim. ActiveAdmin uses it for default RESTful actions. – coreyward Mar 11 '12 at 04:52

1 Answers1

4

Would something like this work for you?

module Display
  def index
    m = self.class.to_s.chomp('Controller').classify.constantize
    @model = m.all
    @model_names = @model.map(&:name).join(', ')
  end
end

In the controllers:

class CarsController < ApplicationController
  include Display 
end

class TrucksController < ApplicationController
  include Display 
end

class VansController < ApplicationController
  include Display 
end

Edit: an attempt to do this without individual controllers

class DisplaysController < ApplicationController
  def index
    @model = params[:model].constantize.all
    @model_names = @model.map(&:name).join(', ')
  end
end

routes.rb

match "display" => "display#index", :as => :display

In a view

link_to "Display Cars", display_path(:model => "Car")
link_to "Display Trucks", display_path(:model => "Truck")
link_to "Display Vans", display_path(:model => "Van")

Note: If you've heard of extend for modules and are wondering why/when to use include vs extend, see What is the difference between include and extend in Ruby? (basically include is for instances, extend for class methods).

Community
  • 1
  • 1
Kyle
  • 21,978
  • 2
  • 60
  • 61
  • Very good! I'm going to hold out for a bit though if you don't mind. If I can find the answer I'm thinking of, I shouldn't even need controllers for each of the models – Kyle Macey Mar 11 '12 at 04:42
  • @KyleMacey - I think my edit will work for you but I have not tested. Let me know if you try it and it doesn't work so I can remove it. – Kyle Mar 11 '12 at 04:58
  • Rather than using `Object.const_get` you can use `constantize`. You can shorten that whole line up to `m = name.chomp('Controller').classify.constantize`. – coreyward Mar 11 '12 at 05:05
  • 1
    I thought it might be useful to note when to use `include` vs. `extend` which people may well have heard of, so I added that at the bottom of this answer (above) as a note. – Michael Durrant Mar 11 '12 at 05:25
  • The code `self.class.to_s.chomp('Controller')` can be replaced with `controller_name` – Harish Shetty Mar 11 '12 at 18:09
  • I might have to go with your original method. I don't want to sacrifice clean routing on behalf of my own laziness. Having `/vans` and `/trucks` seems to make the most sense to me. Thanks for great answers! – Kyle Macey Mar 12 '12 at 00:46
  • @KyleMacey did you settle on a method? I'm curious. – Kyle Mar 14 '12 at 03:44
  • @Kyle Ended up writing a custom generation file to regenerate and populate the controllers when I want to make changes. I couldn't get the Module to work right, and I need pretty routes. I'll post as an answer so you can see. – Kyle Macey Mar 14 '12 at 04:25