Как определить связь между активной записью и активным ресурсом с помощью внешних ключей?

У меня есть локальная пользовательская модель, которая использует activerecord. У пользователя есть поле электронной почты. У меня также есть модель активного ресурса, называемая задачами, в которой есть поле created_by, в котором хранится адрес электронной почты отправляющего пользователя. Я хотел бы связать их, но я борюсь с правильным синтаксисом или даже с тем, возможно ли это.

Основная ветвь ActiveResource, похоже, даже не поддерживает внешний ключ. Я нашел альтернативную ветку, но все равно ничего не заработало.

class User < ActiveRecord::Base
   has_many :tasks
end

class Task < ActiveResource::Base
  belongs_to :user
  schema do
    string 'created_by' #email
    # other fields
  end
end



Ответы (2)


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

class User < ActiveRecord::Base
  has_many :tasks, foreign_key: "uid"
end

Теперь проблема в том, что вы не можете использовать belongs_to для ActiveResource, поэтому, если вам не нужно извлекать user из экземпляра класса Task, вы можете просто удалить его, и другая сторона отношения все еще будет работать, однако, если вам нужно чтобы получить user, вам нужно будет либо реализовать свой собственный метод поиска следующим образом:

class Task < ActiveResource::Base
  schema do
    string 'created_by' #email
    # other fields
  end

  def user
    @user ||= User.find self.user_id # use the attribute name that represents the foreign key
  end

  def user=(user)
    @user = user
    self.update_attribute(:user_id, user.id)
  end
end

Это в основном будет вести себя так же, как вы ожидаете от модели ActiveRecord, однако это может быть утомительно, если у вас есть несколько ассоциаций, поэтому вместо этого вы можете расширить модуль ActiveResource, добавив belongs_to следующим образом:

module BelongsToActiveResource

    def self.included(base)
      base.extend(ClassMethods)
    end

    module ClassMethods

    def belongs_to( name, options = {} )
      class_eval %(
        def #{name}
          @#{name} ||= name.to_s.classify.find( name.id )
        end

        def #{name}=(obj)
          @#{name} ||= obj
          self.update_attribute((name.to_s + "_id").to_sym, @#{name}.id
        end
      )
    end

  end

end   

ActiveResource::Base.class_eval { include BelongsToActiveResource }

Это позволит вам использовать own_to на любой модели ActiveResource.

PS: приведенное выше решение было вдохновлено https://stackoverflow.com/a/8844932/3770684

person cousine    schedule 24.06.2014
comment
Я попробовал это с патчем обезьяны, который вы предложили, но когда я запускаю «User.last.tasks», я получаю «NoMethodError: неопределенный метод «relation_delegate_class» для Task: Class» - person Simmo; 24.06.2014
comment
Какие версии ruby ​​и rails вы используете? - person cousine; 26.06.2014
comment
Рельсы 4.1.0 и Руби 2.1.1 - person Simmo; 26.06.2014
comment
Извините, это было давно, я попробую создать для него манекен, потому что я не могу воссоздать его на Rails 4.0 и обновить свое решение. - person cousine; 29.06.2014
comment
Тогда я начислю 50 баллов за усилия, прежде чем они закончатся. - person Simmo; 30.06.2014

Вы не можете, но вы можете подделать это, самостоятельно реализовав методы доступа.

class User < ActiveRecord::Base
  #has_many :tasks
  def tasks
    Task.find(:all, params: {created_by: email})
  end
end

class Task < ActiveResource::Base
  #belongs_to :user
  def user
    User.where(email: created_by).first
  end

  schema do
    string 'created_by' #email
    # other fields
  end
end

Это позволит вам писать код как если бы ваши объекты были связаны (например, User.first.tasks.length). Однако на самом деле они не соединены. Это означает, что вызов User.first.tasks попадет в базу данных, а затем сделает дополнительный HTTP-запрос для получения Tasks. В зависимости от того, как структурирован ваш код, вы можете столкнуться с неожиданными проблемами производительности.

Кроме того, вы не можете запустить один запрос, чтобы получить пользователя и все связанные с ним задачи (поскольку это два отдельных хранилища данных), и вы не можете делать такие причудливые вещи, как User.joins(:tasks).where({tasks: field_1: true}).

person James Mason    schedule 24.06.2014