Rails form_for that uses STI base class
Asked Answered
S

2

12

I've got a pretty simple (I think) single-table inheritance (STI) setup in my Rails app.

There is a User model with a nested resource Post. Using STI, I have it so that some Posts can be Post::Urgent objects.

I noticed that my URL helpers like <%= [@user, @post] %> needed to be hard-coded to <%= user_post_path[@user, @post] %> or else I'd end up seeing errors about Rails not finding the user_post_urgent_path method. Okay, that was reasonably easy.

(An alternate way of doing this is also <%= [@user, post: @post] %>.)

Well, for some reason I'm not able to figure out how to make the form_for method adjusted in the same way. When I write simply

<%= form_for [@user, @post] do |f| %>

, I get similar errors to the URL helper case, but in the form context: undefined method 'user_post_urgen_path'.

I fixed this by specifying:

<%= form_for [@user, @post], url: :user_post do |f| %>

But this doesn't completely work, because when I go to submit the form, I get problems in my controller, saying that strong parameters line params.require(:post) failed:

param is missing or the value is empty: post

If I inspect the params I find that the form is passing a post_urgent object and not a post object.

I could, of course, manually put in some logic that always says if !params[:post] and params[:post_urgent], then params[:post] = params[:post_urgent]. But that just seems way too hacky, especially for Rails.

Is there a better way to make a form like this "just work" regardless of what subclass of the Post model it actually happens to be?

Shorts answered 24/10, 2015 at 1:25 Comment(0)
F
29

Not sure if you found a solution already, but I am using the following for my forms

= form_for [@user, @post.becomes(Post)] do |f|
  - f.object = @post.becomes @post.class

reference: http://thepugautomatic.com/2012/08/rails-sti-and-form-for/

Friendly answered 14/1, 2016 at 7:44 Comment(1)
It works, but Yuck! Seems like there should be a better way, but thanks!Herpes
S
0

I had some nested models initialized in the controller, empty unsaved models to work with accepts_nested_attribues_for and becomes empties them for some reason, so instead, I acted on the controller strong params, not the cleanest, I know.

  def unpermitted_model_params
    polymorphic_form_params = params.to_unsafe_hash
        .slice('sub_model1', 'sub_model2')
    form_values = polymorphic_form_params.first.to_a.second
    ActionController::Parameters.new(parent_model: form_values)
  end

  def allowed_params
    unpermitted_model_params.require(:parent_model)
                            .permit(:type, :etc, :etc)
  end
Soph answered 2/6, 2020 at 8:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.