1

필자는 백엔드 사용자에게 요소를 정렬 할 수있는 권한을 부여 할 우려가 있습니다. 나는 그것을 몇 가지 다른 요소로 사용한다. 당신이 무엇을서비스 개체에서이 문제를 어떻게 변형해야합니까?

require 'active_support/concern' 

module Rankable 
    extend ActiveSupport::Concern 
    included do 
    validates :row_order, :presence => true 
    scope :next_rank, lambda { |rank| where('row_order > ?',rank).order("row_order asc").limit(1)} 
    scope :previous_rank, lambda { |rank| where('row_order < ?',rank).order("row_order desc").limit(1)} 
    scope :bigger_rank, order("row_order desc").limit('1') 
    before_validation :assign_rank 
    end 

    def invert(target) 
    a = self.row_order 
    b = target.row_order 
    self.row_order = target.row_order 
    target.row_order = a 
    if self.save 
     if target.save 
     true 
     else 
     self.row_order = a 
     self.save 
     false 
     end 
    else 
     false 
    end 
    end 

    def increase_rank 
    return false unless self.next_rank.first && self.invert(self.next_rank.first) 
    end 

    def decrease_rank 
    return false unless self.previous_rank.first && self.invert(self.previous_rank.first) 
    end 

    private 
    def assign_default_rank 
    if !self.row_order 
     if self.class.bigger_rank.first 
     self.row_order = self.class.bigger_rank.first.row_order + 1 
     else 
     self.row_order=0 
     end 
    end 
    end 
end 

답변

2

내가 우려가 좋은 선택이라고 생각 : 레일 커뮤니티가 관심과 콜백에 대한 꽤 보컬 것 같다, 내가 더 나은 다음 코드를 모델링하는 방법에 대한 몇 가지 포인터를 가지고 싶습니다 (특히 ActiveRecord는이 두 가지를 잘 수행하기 때문에 유효성 검사와 범위를 사용하여) 달성하려고합니다. 그러나 유효성 검사와 범위를 제외하고 우려 사항을 다른 곳으로 옮기고 싶다면 여기에 가능성이 있습니다.

class Rank 
    def initialize(rankable) 
    @rankable = rankable 
    @klass = rankable.class 
    end 

    def number 
    @rankable.row_order 
    end 

    def increase 
    next_rank ? RankableInversionService.call(@rankable, next_rank) : false 
    end 

    def decrease 
    previous_rank ? RankableInversionService.call(@rankable, previous_rank) : false 
    end 

    private 

    def next_rank 
    @next_rank ||= @klass.next_rank.first 
    end 

    def previous_rank 
    @previous_rank ||= @klass.previous_rank.first 
    end 
end 

우리가 RankableInversionService을 만들 수있는 #invert 방법을 추출하려면 (위에서 언급 한) : 당신이 정수로 표현되어 있지만 그 자체가 목적입니다 될 수 순위의 개념을 가지고있는 것처럼 그냥 코드를 찾는 것 같다 :

class RankableUpdateService 
    def self.call(rankable) 
    new(rankable).call 
    end 

    def initialize(rankable) 
    @rankable = rankable 
    @klass = rankable.class 
    end 

    def call 
    @rankable.rank = bigger_rank unless @rankable.ranked? 
    @rankable.save 
    end 

    private 

    def bigger_rank 
    @bigger_rank ||= @klass.bigger_rank.first.try(:rank) 
    end 
end 

:

class RankableInversionService 
    def self.call(rankable, other) 
    new(rankable, other).call 
    end 

    def initialize(rankable, other) 
    @rankable = rankable 
    @other = other 
    @original_rankable_rank = rankable.rank 
    @original_other_rank = other.rank 
    end 

    def call 
    @rankable.rank = @other.rank 
    @other.rank = @rankable.rank 

    if @rankable.save && @other.save 
     true 
    else 
     @rankable.rank = @original_rankable_rank 
     @other.rank = @original_other_rank 

     @rankable.save 
     @other.save 

     false 
    end 
    end 
end 

는 객체를 저장하기 전에 기본 순위를 할당하는 RankableUpdateService을 가질 수 콜백을 추출하려면 당신이있는 그대로를 사용하는 경우이 코드에 문제가 확신

module Rankable 
    extend ActiveSupport::Concern 

    included do 
    # validations 
    # scopes 
    end 

    def rank 
    @rank ||= Rank.new(self) 
    end 

    def rank=(rank) 
    self.row_order = rank.number; @rank = rank 
    end 

    def ranked? 
    rank.number.present? 
    end 
end 

,하지만 당신은 개념을 얻을 : 이제 우려된다. 전반적으로 나는 여기에 할 수있는 유일한 일은 순위 객체를 추출하는 것 뿐이라는 것 이외에는 그 복잡성이 너무 복잡해서 캡슐화 할 수 없을 것이라고 생각합니다.