2010-09-21 2 views
32

По умолчанию ActiveRecord берет все поля из соответствующей таблицы базы данных и создает общедоступные атрибуты для всех из них.Есть ли способ сделать атрибуты Rails ActiveRecord частными?

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

Итак, есть ли способ сделать некоторые атрибуты буквально private?

Или, может быть, я должен перейти к другому ORM?

ответ

29

Jordini была большая часть пути там

Большинство active_record происходит в method_missing. Если вы определяете метод фронт, он не ударит method_missing для этого метода, и использовать ваши вместо (эффективно перезапись, но на самом деле не)

class YourModel < ActiveRecord::Base 

    private 

    def my_private_attribute 
    self[:my_private_attribute] 
    end 

    def my_private_attribute=(val) 
    write_attribute :my_private_attribute, val 
    end 

end 
+1

Любая причина, по которой я не мог/не мог использовать следующее, чтобы выполнить это? private attr_accessor my_private_attribute –

+2

@TC: потому что они не будут правильно отслеживать атрибуты. методы write_attribute/read_attribute - это то, как вы фактически взаимодействуете с active_record –

+0

, write_attribute не будет сохранять значение DB. Один из них должен был бы назвать self.save впоследствии, чтобы фактически обновить запись в БД. – Magne

5

хорошо, вы всегда можете переопределить методы ...

class YourModel < ActiveRecord::Base 

    private 

    def my_private_attribute 
    self[:my_private_attribute] 
    end 

    def my_private_attribute=(val) 
    self[:my_private_attribute] = val 
    end 

end 
+0

кажется, что это дает ошибку при использовании обновления от класса модели. – NicolasWebDev

1

Вы можете сделать существующий метод частного:

YourClass.send(:private, :your_method) 
+1

это действительно не работает с ActiveRecord, к сожалению, поскольку методы доступа на самом деле не определены, они создаются с помощью метода method_missing и немного мета-программирования. – brad

6

Наткнулся на это в последнее время. Если вы хотите частное письмо, чтение и публичное чтение примерно так

class YourModel < ActiveRecord::Base 

    attr_reader :attribute 

    private 

    attr_accessor :attribute 


end 

, похоже, подходит для меня. Вы можете играть с attr_reader, attr_writer и attr_accessor, чтобы решить, что должно быть открыто, и что должно быть закрытым.

+1

Я уверен, что это не будет работать с обычными атрибутами AR, поскольку они не хранятся в переменных экземпляра (с которыми работают методы attr_ *). –

+1

Я искал этот ответ везде! Похоже, что это сработало и было ТОЧНО, что я искал. Благодаря! – ootoovak

+0

С внешней модели я могу сделать 'your_model_instance [: my_private_attribute] =" Foo "' и изменить значение атрибута. Очень страшный! –

0

Выполнение функции private генерирует ошибку ActiveRecord.

Я поставил код контроля доступа в перезаписанном методе публичного сеттер путем проверки абонента:

def my_private_attribute=(val) 
    if (caller.first.include?('active_record/base.rb') || caller.first.include?('app/models/myclass.rb')) 
    self[:my_private_attribute] = val 
    else 
    raise Exception.new("Cannot set read-only attribute.") 
    end 
end 
1

Для меня метод обоих Отто и jordinl работает отлично и сделать RSpec для объекта класса, чтобы пройти:

object.should_not respond_to :attribute 

но когда я использую jordinl метод, у меня есть сообщение устаревания, чтобы не писать в базу данных напрямую, а использовать вместо attr_writer.

UPDATE:

Но по-настоящему «право» Metod сделать это оказывается просто. Благодаря Младену Яблановичу и Кристоферу Кретцигу from here. Для того, чтобы предопределенный метод частный или защищенный ... просто переопределить его:

Class Class_name 

    private :method_name 
    protected :method_name_1 
end 

Что важно, вам не нужно переписать логику, определенные ранее метода.

Смежные вопросы