-->

superclass mismatch for class User - inheriting fr

2019-07-28 20:23发布

问题:

I am trying to figure out my superclass mismatch error. All the posts I've read about this describe the problem as being that User is defined twice as a class in my application.

In my case, it isn't defined twice. I have a services folder and within that I have a user folder (for user service classes). In that user folder, I have a file called organisation_mapper_service.rb, with:

class User < ActiveRecord::Base
      class OrganisationMapperService
        def self.call(user: u)
          new(user: user).call
        end

        def initialize(user: u)
          self.user = user
        end

        def call
          if matching_organisation.present?
            # user.organisation_request.new(organisation_id: matching_organisation.id)
            # user.update_attributes!(organisation_id: matching_organisation.id)
          else
            #SystemMailer.unmatched_organisation(user: user).deliver_now
          end
        end

        private

        attr_accessor :user

        def matching_organisation
          User::OrganisationMapperService.new(user).matching_organisation
        end
      end
    end

Separate to that, I have my user model which defines user as:

class User < ApplicationRecord

I thought it should be fine to define the service class in the way I have because it inherits from ActiveRecord::Base rather than ApplicationRecord.

Can anyone see what I've done wrong here? Where else could I look for a second definition of User?

TAKING SERGIO'S SUGGESTION

I change the user organisation mapper service to open as follows:

class User::OrganisationMapperService < ActiveRecord::Base

But that then gives an error with my Users::OrgRequestsController which has new defined as follows:

def new
    @all_organisations    = Organisation.select(:title, :id).map { |org| [org.title, org.id] }
    @org_request = OrgRequest.new#form(OrganisationRequest::Create)

    matched_organisation = User::OrganisationMapperService.new(current_user).matching_organisation
    @org_request.organisation_id = matched_organisation.try(:id)
  end

the error message then says:

PG::UndefinedTable at /users/4/org_requests/new
ERROR:  relation "user_organisation_mapper_services" does not exist
LINE 8:                WHERE a.attrelid = '"user_organisation_mapper...

**TAKING SERGIO'S SUGGESTION (exactly) **

I change my service class to:

class User::OrganisationMapperService 

But then I get an error that says:

wrong number of arguments (given 1, expected 0)

That error highlights this line of my service class:

def initialize(user: u)
      self.user = user
    end

I don't know what to do about that because I clearly have a user if there is an inheritance from user.

回答1:

Even once you solve all your other issues, you actually have an infinite recursion going on.

User::OrganisationMapperService.call(user: User.first)

Is equivalent to calling:

User::OrganisationMapperService.new(user: User.first).call

Which internally calls matching_organisation, so is sort of equivalent to:

User::OrganisationMapperService.new(user: User.first).matching_organisation

Meanwhile, matching_organisation calls

User::OrganisationMapperService.new(user).matching_organisation

It's just going to go round and round in circles.

The only reason it doesn't is because of the wrong number of arguments (given 1, expected 0) error. This is because it should be User::OrganisationMapperService.new(user: user) rather than User::OrganisationMapperService.new(user) in your matching_organisation method.

Update in response to comment:

From what I understand, the User::OrganisationMapperService is a service class that does the job of finding some Organisation and then performing some sort of work.

The User::OrganisationMapperService#matching_organisation method should actually contain the code that returns the matching organisation for the given user. The implementation will completely depend on how you have structured your database, but I'll give a couple of examples to put you on the right track or give you ideas.

First, Your organisations table may have a user_id column. In this case you could do a simple query on the Organisation model and perform a search using the user's id:

class User::OrganisationMapperService
  def matching_organisation
    # find the organisation and cache the result
    @matching_organisation ||= ::Organisation.where(user_id: user).first
  end
end

Alternatively, you may have some sort of join table where there may be multiple Users at an Organisation (just for this example let us call this table 'employments'):

class Employment < ApplicationRecord
  belongs_to :user
  belongs_to :organisation
end

We can add scopes (this is a must read) to the Organisation model to assist with the query:

class Organisation < ApplicationRecord

  has_many :employments
  has_many :users, through: :employments 

  scope :for_user, ->(user) {
    # return organisations belonging to this user
    joins(:users).merge( Employment.where(user_id: user) )
  }

end

Then finally, the OrganisationMapperService#matching_organisation method becomes:

class User::OrganisationMapperService
  def matching_organisation
    # find the organisation and cache the result
    @matching_organisation ||= ::Organisation.for_user(user).first
  end
end


回答2:

You are defining User class with two separate parent classes. Don't do that.

It should be

class User::OrganisationMapperService

This way, your existing User class will be loaded and used, rather than a new one created.

I thought it should be fine to define the service class in the way I have because it inherits from ActiveRecord::Base rather than ApplicationRecord.

The service class in your example doesn't inherit from anything.