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
Difference Between Include and Extend in Ruby
Ruby: How to Post a File Via Http as Multipart/Form-Data
Do..End VS Curly Braces For Blocks in Ruby
Rails :Dependent =≫ :Destroy VS :Dependent =≫ :Delete_All
No Such File to Load - Rubygems (Loaderror)
Your Ruby Version Is 2.0.0, But Your Gemfile Specified 2.1.0
Best Way to Create Custom Config Options For My Rails App
Ruby 2.0.0P0 Irb Warning: "Dl Is Deprecated, Please Use Fiddle"
When to Use Lambda, When to Use Proc.New
How to Get the Name of the Calling Method
How to Download a Binary File Over Http
Begin, Rescue and Ensure in Ruby
How to Run Rake Tasks from Within Rake Tasks