2010-09-21 36 views
32

Theo mặc định, ActiveRecord lấy tất cả các trường từ bảng cơ sở dữ liệu tương ứng và tạo các thuộc tính công khai cho tất cả chúng.Có cách nào để biến các thuộc tính Rails ActiveRecord thành riêng tư không?

Tôi nghĩ rằng nó hợp lý không phải để đặt tất cả các thuộc tính trong một mô hình công khai. Thậm chí nhiều hơn, phơi bày các thuộc tính có nghĩa là để sử dụng nội bộ làm lộn xộn giao diện của mô hình và vi phạm nguyên tắc đóng gói.

Vì vậy, có cách nào để làm cho một số thuộc tính theo nghĩa đen là private không?

Hoặc, có lẽ tôi nên chuyển sang một số ORM khác?

Trả lời

29

Jordini là hầu hết các con đường đó

Hầu hết các active_record xảy ra trong method_missing. Nếu bạn xác định phương pháp lên phía trước, nó sẽ không đánh method_missing cho phương pháp đó, và sử dụng của bạn thay (ghi đè lên một cách hiệu quả, nhưng không thực sự)

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

Bất kỳ lý do nào tại sao tôi không/không thể sử dụng những điều sau đây để thực hiện việc này? riêng attr_accessor my_private_attribute –

+2

@TC: vì những người đó sẽ không thực sự theo dõi các thuộc tính một cách chính xác. phương thức write_attribute/read_attribute là cách bạn giao tiếp với active_record –

+0

thực sự, write_attribute sẽ không tồn tại giá trị cho DB. Người ta sẽ phải gọi self.save sau đó để thực sự cập nhật hồ sơ trong DB. – Magne

5

tốt, bạn luôn có thể ghi đè lên các phương pháp ...

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

Dường như điều này gây ra lỗi khi sử dụng bản cập nhật từ lớp mô hình. – NicolasWebDev

1

Bạn có thể thực hiện một phương pháp hiện tin:

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

điều này thực sự không hoạt động với ActiveRecord không may vì các phương thức accessor không thực sự được định nghĩa, chúng được tạo với method_missing và một chút lập trình meta. – brad

6

stumbled khi này thời gian gần đây. Nếu bạn muốn đọc và đọc riêng tư, hãy đọc và đọc công khai nội dung nào đó như thế này

có vẻ phù hợp với tôi. Bạn có thể fiddle với attr_reader, attr_writer và attr_accessor để quyết định những gì cần được tiếp xúc và những gì nên được tư nhân.

+1

Tôi khá chắc chắn rằng điều này sẽ không làm việc với các thuộc tính AR thông thường, vì chúng không được lưu trữ trong các biến mẫu (mà các phương thức attr_ * làm việc với). –

+1

Tôi đã tìm câu trả lời này ở khắp mọi nơi! Có vẻ như nó đã hoạt động và chính xác là những gì tôi đang tìm kiếm. Cảm ơn! – ootoovak

+0

Từ mô hình bên ngoài, tôi có thể thực hiện 'your_model_instance [: my_private_attribute] =" Foo "' và thay đổi giá trị thuộc tính. Rất xấu! –

0

Đặt cài đặt ở chế độ riêng tư sẽ tạo ra lỗi ActiveRecord.

Tôi đặt mã kiểm soát truy cập trong phương pháp ghi đè các setter công cộng bằng cách kiểm tra người gọi:

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

Đối với tôi phương pháp từ cả Otto và jordinl đang làm việc tốt và làm cho rspec cho đối tượng của lớp để vượt qua:

object.should_not respond_to :attribute 

Nhưng khi tôi sử dụng phương pháp jordinl, tôi có thông báo không dùng nữa để viết trực tiếp vào cơ sở dữ liệu, nhưng thay vào đó hãy sử dụng attr_writer.

CẬP NHẬT:

Nhưng thực sự "đúng" metod để làm nó trở nên đơn giản. Nhờ Mladen Jablanović và Christopher Creutzig from here. Để đặt phương thức được xác định trước riêng tư hoặc được bảo vệ ... chỉ cần xác định lại phương thức đó:

Điều quan trọng là bạn không cần phải viết lại logic của phương thức đã xác định trước đó.

Các vấn đề liên quan