简体   繁体   中英

How to use form_with with self join in rails?

I have a User model which can have many child accounts. I have set up the model as below

class User < ApplicationRecord
  has_many :child_accounts, class_name: "User", foreign_key: "parent_account_id"
  belongs_to :parent_account, class_name: "User", optional: true
end

I have created a ChildAccountsController to handle the child accounts creation etc. and defined routes as below.

resources :users do
  resource :child_accounts
end

But I can get form_with to work in this situation. as

form_with(model: [current_user, @child_account], local: true) do
#...
end 

form_with infers the url from the model class since both of them are User. the path it infers user_user_path instead of user_child_accounts_path .

So, is there a rails way to create forms with self joins? Or do I have manually handle this case?

To start with you have a pluralization error:

resources :users do
  resources :child_accounts 
end

resource is used to declare singular resources .

But the polymorphic route helpers will not be able route to that path automatically anyways, when you pass model instances to form_for , form_with , link_to and button_to they deduce the name of route helper method by calling #model_name and using the methods of ActiveModel::Naming . Since @child_account is an instance of User you get user_users_path . The polymorphic routing helpers are not aware of your associations.

It does not matter at all here if you use form_for or form_with as both use the exact same methods to figure out a path from a model or array of models.

You either need to explicitly pass the url:

form_with(model: @child_account, url: user_child_accounts_path(current_user), local: true) do
#...
end

Or use single table inheritance :

class AddTypeToUsers < ActiveRecord::Migration[6.0]
  def change
    change_table :users do |t|
      t.string :type
    end
  end
end
class User < ApplicationRecord
  has_many :child_accounts, 
    foreign_key: "parent_account_id",
    inverse_of: :parent_account
end

class ChildAccount < User
  belongs_to :parent_account, 
    class_name: "User",
    inverse_of: :child_accounts
end
class ChildAccountsController < ApplicationController
  def new
    @child_account = current_user.child_accounts.new
  end

  def create
    @child_account = current_user.child_accounts.new(child_account_params)
    # ...
  end

  private
  def child_account_params
    params.require(:child_account)
          .permit(:foo, :bar, :baz)
  end
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM