Sti, One Controller

STI, one controller

First. Add some new routes:

resources :highlights, :controller => "ads", :type => "Highlight"
resources :bargains, :controller => "ads", :type => "Bargain"

And fix some actions in AdsController. For example:

def new
@ad = Ad.new()
@ad.type = params[:type]
end

For best approach for all this controller job look this comment

That's all. Now you can go to localhost:3000/highlights/new and new Highlight will be initialized.

Index action can look like this:

def index
@ads = Ad.where(:type => params[:type])
end

Go to localhost:3000/highlights and list of highlights will appear.

Same way for bargains: localhost:3000/bargains

etc

URLS

<%= link_to 'index', :highlights %>
<%= link_to 'new', [:new, :highlight] %>
<%= link_to 'edit', [:edit, @ad] %>
<%= link_to 'destroy', @ad, :method => :delete %>

for being polymorphic :)

<%= link_to 'index', @ad.class %>

STI with a Single Controller

In that case you'd need to communicate the type to create to the controller somehow.

This is most easily established by including a hidden field in the form which has a value of the type you want to create.

Assuming your block variable for the form is f

<%= f.hidden_field :type, :value => "Excercise" %>

Then you can build a goal like this:

current_user.goals.build(type: params[:type])

You can easily see how this can be very dangerous, you should always be doubly careful when using user submitted data.

To guard against a malicious user, you could set a constant in your controller

AcceptedModels = ["Excercise", "Yoga", "Water"]

def accepted_type
(AcceptedModels & params[:type]).first
end

If you also want to hide your internal structure, you could use a hash and send any identifier

AcceptedModels = {"0": "Excercise", "1": "Yoga", "2": "Water"}

def accepted_type
AcceptedModels.fetch(params[:type], nil)
end

in either case you can then build your goal like this:

current_user.goals.build(type: accepted_type)

The biggest downside with this is that you will have to keep the AcceptedModels updated whenever you add/remove more goals

Rails single table inheritance. Shared controller, howto Update (CRUD)

There is indeed a much more elegant solution. Just change your form_for declaration and add the as option, like this:

<%= form_for(@user, as: :user, url: user_path(@user), method: :put) do |f| %>

That way in your controller your parameters will be scoped under the user key instead of the model's class.

STI and Controller

In my opinion the best way is to do it like this: (I am not sure if this is the best and more efficient way)

First. Add some new routes:

resources :cars, :controller => "vehicle", :type => "Car"
resources :buses, :controller => "vehicle", :type => "Bus"

Add a private method to your controller to convert your type param to the actual class constant you want to use:

def vehicle_type
params[:type].constantize
end

Then in the controller actions you can do:

def new
vehicle_type.new
end

def create
vehicle_type.new(params)
# ...
end

def index
vehicle_type.all
end

URLS

<%= link_to 'index', :cars %>
<%= link_to 'new', [:new, :car] %>
<%= link_to 'edit', [:edit, @vehicle] %>
<%= link_to 'destroy', @vehicle, :method => :delete %>

for being polymorphic :)

<%= link_to 'index', @vehicle.class %>

PS: My answer was taken from stackoverflow.com/questions/5246767/sti-one-controller and my experience



Related Topics



Leave a reply



Submit