STI, one controller

后端 未结 5 2038
谎友^
谎友^ 2020-11-27 09:49

I\'m new to rails and I\'m kind of stuck with this design problem, that might be easy to solve, but I don\'t get anywhere: I have two different kinds of advertisements: high

5条回答
  •  甜味超标
    2020-11-27 10:25

    [Rewritten with simpler solution that works fully:]

    Iterating on the other answers, I have come up with the following solution for a single controller with Single Table Inheritance that works well with Strong Parameters in Rails 4.1. Just including :type as a permitted parameter caused an ActiveRecord::SubclassNotFound error if an invalid type is entered. Moreover, type is not updated because the SQL query explicitly looks for the old type. Instead, :type needs to be updated separately with update_column if it is different than what is current set and is a valid type. Note also that I've succeeded in DRYing up all lists of types.

    # app/models/company.rb
    class Company < ActiveRecord::Base
      COMPANY_TYPES = %w[Publisher Buyer Printer Agent]
      validates :type, inclusion: { in: COMPANY_TYPES,
        :message => "must be one of: #{COMPANY_TYPES.join(', ')}" }
    end
    
    Company::COMPANY_TYPES.each do |company_type|
      string_to_eval = <<-heredoc
        class #{company_type} < Company
          def self.model_name  # http://stackoverflow.com/a/12762230/1935918
            Company.model_name
          end
        end
      heredoc
      eval(string_to_eval, TOPLEVEL_BINDING)
    end
    

    And in the controller:

      # app/controllers/companies_controller.rb
      def update
        @company = Company.find(params[:id])
    
        # This separate step is required to change Single Table Inheritance types
        new_type = params[:company][:type]
        if new_type != @company.type && Company::COMPANY_TYPES.include?(new_type)
          @company.update_column :type, new_type
        end
    
        @company.update(company_params)
        respond_with(@company)
      end
    

    And routes:

    # config/routes.rb
    Rails.application.routes.draw do
      resources :companies
      Company::COMPANY_TYPES.each do |company_type|
        resources company_type.underscore.to_sym, type: company_type, controller: 'companies', path: 'companies'
      end
      root 'companies#index'
    

    Finally, I recommend using the responders gem and setting scaffolding to use a responders_controller, which is compatible with STI. Config for scaffolding is:

    # config/application.rb
        config.generators do |g|
          g.scaffold_controller "responders_controller"
        end
    

提交回复
热议问题