Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
276 views
in Technique[技术] by (71.8m points)

ruby - 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?

question from:https://stackoverflow.com/questions/65873515/how-to-use-form-with-with-self-join-in-rails

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...