0

Suppose I have a Rails 4 application that manages Widget objects, and using Simple Table Inheritance I have specialisations Widget::Foo and Widget::Bar.

I would like to manage all my Widget objects through a single WidgetsController.

I have the following models:

class Widget < ActiveRecord::Base; end

class Widget::Foo < Widget
  # Foo specific details...
end

class Widget::Bar < Widget
  # Bar specific details...
end

And a simple controller:

class WidgetsController < ApplicationController
  def index
    @widgets = Widget.all
  end

  def show
    @widget = Widget.find(params[:id])
  end
end

My routes include

resources :widgets, only: [:index, :show}

In my index.html.haml I have something like:

- @widgets.each do |widget|
  = link_to "View your widget!", [@widget]

Which is where everything goes wrong.

Between url_for and polymorphic_path Rails will attempt to find a widget_foo_path, rather than using the extant widget_path.

I would rather not add additional routes, or controllers, and I would prefer not to specify the url helper manually. Is there a way to tell Rails that Widget::Foo and Widget::Bar objects should be linked to using the widget_path helper?

Himanshu Patel
  • 173
  • 1
  • 2
  • 7
thomasfedb
  • 5,990
  • 2
  • 37
  • 65

1 Answers1

0

I ended up resolving the issue by creating a mixin:

module GenericSTIRoutes
  def initialize(klass, namespace = nil, name = nil)
    super(klass, namespace, name)

    superklass = klass

    while superklass.superclass != ActiveRecord::Base
      superklass = superklass.superclass
    end

    @param_key          = _singularize(superklass.name)
    @route_key          = ActiveSupport::Inflector.pluralize(@param_key)
    @singular_route_key = @param_key.dup
    @route_key << "_index" if @plural == @singular
  end
end

And then modifying Widget.model_name as follows:

def self.model_name
  @_model_name ||= Class.new(ActiveModel::Name) do
    include GenericSTIRoutes
  end.new(self, nil)
end
thomasfedb
  • 5,990
  • 2
  • 37
  • 65