Rails 5 - 服务类,用于查找具有与组织的域名

时间:2016-11-20 03:41:34

标签: ruby-on-rails ruby methods service

我正在尝试学习如何使用Rails 5(通常),但具体来说,我试图学习如何使用服务类。

我正在尝试编写一个服务类,该服务类将用户的给定电子邮件地址(用户具有名为:email的属性)映射到组织的域名。组织具有名为:email_format的属性。我使用该属性来保存" @"。

之后的电子邮件地址部分

当用户创建帐户时,我想要使用他们用来注册的电子邮件地址,并将@之后的位与我所知道的每个组织匹配,并尝试找到匹配的组织。< / p>

我对此的尝试显然是错误的,但我正在努力弄清楚原因。

我有称为User,Organization和OrgRequest的资源。协会是:

用户

belongs_to :organisation, optional: true
has_one :org_request

组织

has_many :org_requests 
has_many :users 

OrgRequest

belongs_to :user
belongs_to :organisation

我曾尝试将服务类编写为:

class User::OrganisationMapperService #< ActiveRecord::Base

    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
      User::OrganisationMapperService.new(user: user)
    end

end

然后我有一个组织请求控制器:

class Users::OrgRequestsController < ApplicationController

    before_action      :authenticate_user!, except: [:new, :create, :requested]
  before_action      :set_org_request, only: [:approved, :rejected, :removed]

  # skip_before_action :redirect_for_unrequested_organisation
  # skip_before_action :redirect_for_unknown_organisation

  def index
    organisation = Organisation.find_by(owner_id: current_user.id)
    return redirect_to(user_path(current_user.id)) if organisation.nil?

    @org_requests = organisation.org_requests
  end

  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

  def create
    @org_request = OrgRequest.new(org_request_params)
    @org_request.user_id = current_user.id

    if @org_request.save
      OrgRequest::ProcessService.new(org_request).process
      return redirect_to(user_path(current_user),
        flash[:alert] => 'Your request is being processed.')
    else
      # Failure scenario below
      @all_organisations    = Organisation.select(:title, :id).map { |org| [org.title, org.id] }

      render :new
    end
  end

  def requested
    # Need help  - if this is contained in form inputs - how do i stop from overriding the submit path?

    redirect_to(user_path(current_user))
    #not sure about this - a similar redirect isnt required for articles or project create
  end

  def approve
    @org_request = current_user.organisation.org_requests.find(params[:id])

    if @org_request.state_machine.transition_to!(:approved)
      flash[:notice] = "You've added this member."
      redirect_to org_requests_path
    else
      flash[:error] = "You're not able to manage this organisation's members"
      redirect_to :index
    end
  end

  def remove
    @org_request = current_user.organisation.org_requests.find(params[:id])

    if @org_request.state_machine.transition_to!(:removed)
      flash[:notice] = "Removed from the organisation."
      redirect_to action: :index
      # format.html { redirect_to :index }
      # format.json { render :show, status: :ok, location: @project }
      # redirect_to action: :show, id: project_id
      # add mailer to send message to article owner that article has been approved
    else
      flash[:error] = "You're not able to manage this organisation's members"
      redirect_to(user_path(current_user))
      # redirect_to action: :show, id: project_id
    end
  end

  def decline
    @org_request = current_user.organisation.org_requests.find(params[:id])

    if @org_request.state_machine.transition_to!(:declined)
      flash[:notice] = "You're not eligible to join this organisation"
      redirect_to action: :index
      # redirect_back(fallback_location: root_path)
      # format.html { redirect_to :index }
      # redirect_to action: :show, id: organisation_request.profile
      # add mailer to send message to article owner that article has been approved
    else
      flash[:error] = "You're not able to manage this organisation's members"
      redirect_to(user_path(current_user))
      # redirect_to action: :show, id: organisation_request.profile
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_org_request
      @org_request = OrgRequest.find(params[:id])
      authorize @org_request
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def org_request_params
      params.require(:org_request).permit(:organisation_id, :name) # Need help - not sure if I need to put user id and organisation id in this permission
    end

end

我无法找到另一种方法。当我尝试这个时,我收到了这个错误:

wrong number of arguments (given 1, expected 0)

错误消息突出显示了我的服务类的第7行,其中包含:

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

我之前在这里询问过有关此问题的问题:superclass mismatch for class User - inheriting from ActiveRecord::Base

但我还没有设法抓住建议的偏差或导致问题的原因。这个尝试混合了我从至少10个不同的教程中收集到的建议 - 所以我很欣赏它极不可能是正确的,但是我很难理解这个工作的不同部分如何知道该怎么做尝试不同。

有人能指导我如何尝试推进此尝试吗?

组织映射器装饰器具有:

class User < ActiveRecord::Base
  class OrganisationMapper < ::ApplicationDecorator

    def matching_organisation
      @matching_organisation ||= Organisation.by_email_format(email_format).first
    end

    def email_format
      user.email.split('@').last
    end

    private

    def user
      @model
    end
  end
end

应用程序装饰器有:

class ApplicationDecorator
  def initialize(model)
    @model = model
  end

  private
  def method_missing(method, *args)
    args.empty? ? @model.send(method) : @model.send(method, *args)
  end
end

组织请求服务类具有:

class OrgRequest::CreateService < ActiveRecord::Base

    attr_accessor :org_request

    def self.call(user_id: user_id, organisation_id: org_id)
      new(user_id: user_id, organisation_id: organisation_id).call
    end

    def initialize(user_id: user_id, organisation_id: org_id)
      self.user_id         = user_id
      self.organisation_id = organisation_id
    end

    def call
      self.org_request \
       = OrgRequest.new(user_id: current_user.id,
                                  organisation_id: params[:org_request][:organisation_id])

      if org_request.save
        # send the email
        true
      else
        false
      end
    end


end

下次尝试

我已经尝试了我能想到的每一个变化。我尝试的任何事情对我都没有任何意义,但我可以从任何我能找到的例子中理解。

我的服务类目前有:

class User::OrganisationMapperService #< ActiveRecord::Base

    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.org_request.new(organisation_id: matching_organisation.id)
        # if found create a request for that user to enter the organisation
        if match_domain.present?
          OrgRequest.create(user: @user, organisation_id: @organisation_domain.organisation.id) #if organisation

        # 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
    #   User::OrganisationMapperService.new(user: user).Organisation.by_email_format(email_format).first
    # end

    # def matching_organisation
    #   @matching_organisation ||= Organisation.by_email_format(email_format).first
    # end

    def user_domain
      user.email.split('@').last
    end

    def organisation_domain
      @organisation = Organisation.find_by(email_format: user_domain)
     end

    # def user_email_domain
    # # extract domain from users email
    #  user_email_domain = @user.email.split('@').last
    # end
    def match_domain
      return unless @user_domain == @organisation.email_format
    end

     # find an organisation with a matching domain
    # end

end

显然是错的。错误消息显示:

NameError - undefined local variable or method `organisation' for #<User::OrganisationMapperService:0x007faec6ec06b8>

我无法理解错误信息,因为我已经把&#39; @&#39;在每个组织的实例面前#39;只是试图让这个错误消失。它没有。

请帮忙。

另一个完全无法发送的错误消息

我又尝试编写方法来检查电子邮件域是否与我服务类中的组织电子邮件格式相匹配。

调用方法现在有:

def call
      if user_domain == Organisation.email_format.any?
          OrgRequest.create(user: @user, organisation_id: @organisation_domain.organisation.id) #if organisation
      else
      end
    end

控制台中的错误消息显示:

NoMethodError - undefined method `email_format' for #<Class:0x007faec72d8ac0>

这必须是无稽之谈,因为我的组织表中有一个名为:email_format的属性。在控制台中,我可以写:

o = Organisation.first.email_format
  Organisation Load (3.3ms)  SELECT  "organisations".* FROM "organisations" ORDER BY "organisations"."id" ASC LIMIT $1  [["LIMIT", 1]]

这给了我正在寻找的结果。

我尝试(以我的智慧结束)了解rails如何通信。我无法理解其中任何一个。

下次尝试

接下来猜测调用方法:

def call
      if user_domain == organisation_domain?
          OrgRequest.create(user: @user, organisation_id: @organisation_domain.organisation.id) #if organisation

      else
      end

产生此错误:

NoMethodError - undefined method `organisation_domain?' for #<User::OrganisationMapperService:0x007faec3be3600>:

我似乎无法找到不会产生此错误的单一表达形式。

2 个答案:

答案 0 :(得分:0)

问题似乎在以下一行:

matched_organisation = User::OrganisationMapperService.new(current_user).matching_organisation

应该是这样:

matched_organisation = User::OrganisationMapperService.new(user: current_user).matching_organisation

答案 1 :(得分:0)

我有一个关于代码导师的会议。这就是答案。我希望它可以帮助其他想要学习的人。

Bar