Может ли область по умолчанию принимать аргументы в рельсах?

Я хочу создать область по умолчанию для фильтрации всех запросов в зависимости от текущего пользователя. Можно ли передать текущего пользователя в качестве аргумента в default_scope? (Я знаю, что это можно сделать с помощью обычных областей). Если нет, то какое другое решение?


person alberto911    schedule 11.03.2015    source источник
comment
возможный дубликат Передать аргументы в области действия   -  person ABMagil    schedule 12.03.2015
comment
не тот же вопрос @ABMagil   -  person alberto911    schedule 12.03.2015


Ответы (2)


Вместо использования default_scope, который имеет несколько подводных камней, вам следует рассмотреть возможность использования именованной области с лямбдой. Например scope :by_user, -> (user) { where('user_id = ?', user.id) }

Затем вы можете использовать before_filter в своих контроллерах, чтобы легко использовать эту область во всех необходимых вам действиях.

Это также правильный способ сделать это, поскольку у вас не будет доступа к вспомогательным методам в вашей модели. Ваши модели также никогда не должны беспокоиться о данных сеанса.

Редактировать: как использовать область в before_filter внутри контроллера:

before_filter :set_object, only: [:show, :edit, :update, :destroy]

[the rest of your controller code here]

private
def set_object
   @object = Object.by_user(current_user)
end

очевидно, вы бы изменили это в зависимости от ваших требований. Здесь мы предполагаем, что вам нужен только действительный @object в зависимости от current_user внутри ваших действий show, edit, update и destroy

person Mario    schedule 11.03.2015
comment
Как бы вы назвали область видимости из before_filter? - person alberto911; 12.03.2015

Вы не можете передать аргумент в область по умолчанию, но вы можете иметь условия области по умолчанию, ссылающиеся на хеш-прокси который выполняет свои процедуры каждый раз, когда значение извлекается:

module Proxies
  # ProxyHash can be used when there is a need to have procs inside hashes, as it executes all procs before returning the hash
  # ==== Example
  #   default_scope(:conditions => Proxies::ProxyHash.new(:user_id => lambda{Thread.current[:current_user].try(:id)}))
  class ProxyHash < ::Hash
    instance_methods.each{|m| undef_method m unless m =~ /(^__|^nil\?$|^method_missing$|^object_id$|proxy_|^respond_to\?$|^send$)/}

    def [](_key)
      call_hash_procs(@target, @original_hash)
      ProxyHash.new(@original_hash[_key])
    end

    # Returns the \target of the proxy, same as +target+.
    def proxy_target
      @target
    end

    # Does the proxy or its \target respond to +symbol+?
    def respond_to?(*args)
      super(*args) || @target.respond_to?(*args)
    end

    # Returns the target of this proxy, same as +proxy_target+.
    def target
      @target
    end

    # Sets the target of this proxy to <tt>\target</tt>.
    def target=(target)
      @target = target
    end

    def send(method, *args)
      if respond_to?(method)
        super
      else
        @target.send(method, *args)
      end
    end

    def initialize(*_find_args)
      @original_hash = _find_args.extract_options!

      @target = @original_hash.deep_dup
    end

    private
      # Forwards any missing method call to the \target.
      def method_missing(method, *args, &block)
        if @target.respond_to?(method)
          call_hash_procs(@target, @original_hash)
          @target.send(method, *args, &block)
        else
          super
        end
      end

      def call_hash_procs(_hash, _original_hash)
        _hash.each do |_key, _value|
          if _value.is_a?(Hash)
            call_hash_procs(_value, _original_hash[_key]) if _original_hash.has_key?(_key)
          else
            _hash[_key] = _original_hash[_key].call if _original_hash[_key].is_a?(Proc)
          end
        end
      end
  end
end

Затем в ApplicationController вы можете использовать around_filter для установки/отмены Thread.current[:current_user] в начале/конце каждого запроса:

class ApplicationController < ActionController::Base
  around_filter :set_unset_current_user

  protected
    def set_unset_current_user
      Thread.current[:current_user] = current_user if logged_in?

      yield
    ensure
      Thread.current[:current_user] = nil
    end
end
person roniegh    schedule 10.11.2015