2009-05-14 36 views
6

tôi có phương pháp trong tất cả các mô hình của tôi trông như thế này:phương pháp toàn cầu trong Ruby on Rails mô hình

def formatted_start_date 
    start_date ? start_date.to_s(:date) : nil 
end 

Tôi muốn có cái gì đó tự động viết một phương pháp như thế này đối với từng lĩnh vực datetime trong mỗi mô hình cách tốt nhất để làm điều này là gì?

-C

Trả lời

16

Tôi chỉ cần trả lời câu hỏi này, đó là một bài tập Ruby thú vị.

Thêm phương thức vào một lớp có thể được thực hiện theo nhiều cách, nhưng một trong những cách gọn gàng nhất là sử dụng một số tính năng phản chiếu và đánh giá của Ruby.

Tạo tập tin này trong thư mục lib của bạn như lib/date_methods.rb

module DateMethods 

    def self.included(klass) 

    # get all dates 
    # Loop through the class's column names 
    # then determine if each column is of the :date type. 
    fields = klass.column_names.select do |k| 
        klass.columns_hash[k].type == :date 
       end 


    # for each of the fields we'll use class_eval to 
    # define the methods. 
    fields.each do |field| 
     klass.class_eval <<-EOF 
     def formatted_#{field} 
      #{field} ? #{field}.to_s(:date) : nil 
     end 

     EOF 
    end 
    end 
end 

Bây giờ chỉ cần đưa nó vào bất kỳ mô hình mà cần nó

class CourseSection < ActiveRecord::Base 
    include DateMethods 
end 

Khi bao gồm, các mô-đun sẽ nhìn vào bất kỳ các cột ngày tháng và tạo các phương thức được định dạng_ cho bạn.

Tìm hiểu cách thức hoạt động của công cụ Ruby này. Đó là rất nhiều niềm vui.

Điều đó nói rằng, bạn phải tự hỏi mình nếu điều này là cần thiết. Tôi không nghĩ rằng nó là cá nhân, nhưng một lần nữa, nó là thú vị để viết.

-b-

+2

tại sao sử dụng thu thập và nhỏ gọn trên mảng thay vì chọn? –

+1

Bạn nói đúng. .select sẽ phù hợp hơn ở đây. Tôi đã tìm thấy thời gian khi .collect.compact là nhanh hơn, ngay cả khi nó xuất hiện nó không nên, nhưng trong trường hợp này .select là một sự lựa chọn tốt hơn nhiều. Cảm ơn vì đã bắt được điều đó. Tôi đang tập trung làm những thứ khó nhọc và bỏ lỡ những thứ dễ dàng. –

+0

+1 Thú vị và thú vị. Sẽ tốt hơn nếu bạn sửa câu trả lời (ở đây trên SO) để bao gồm các bình luận của Chris. –

11

Nó trông giống như một cái gì đó giúp ích cho tôi. Hãy thử điều này trong sự giúp đỡ ứng dụng của bạn:

def formatted_date(date) 
    date ? date.to_s(:date) : nil 
end 

Formatting không phải là cái gì đó thực sự thuộc trong mô hình (đối với chính xác lý do bạn đã khám phá ... đặt mã thông thường như vậy trong mỗi mô hình là gây phiền nhiễu)

Nếu bạn thực sự muốn làm như bạn nói mặc dù, sau đó những gì bạn có thể làm là monkeypatch siêu lớp ActiveRecord và thêm chức năng bạn muốn vào đó. Sau đó nó sẽ có sẵn cho tất cả các mô hình của bạn. Hãy coi chừng việc bắt chước khỉ có thể dẫn đến hành vi không thể đoán trước và không xác định được và sử dụng rủi ro của chính bạn! Nó cũng khá hacky :)

class ActiveRecord::Base 
    def formatted_start_date 
     start_date ? start_date.to_s(:date) : nil 
    end 
end 

Chỉ cần dính rằng ở đâu đó sẽ được chạy trước bất cứ điều gì khác trong ứng dụng của bạn sẽ được, và nó sẽ tự động thêm phương pháp để các lớp cơ sở của mô hình của bạn, làm cho nó có sẵn để sử dụng .

Hoặc bạn có thể tạo bản mix cho tất cả các mô hình của mình, nhưng điều đó có vẻ hơi quá mức đối với một phương thức duy nhất.

+1

+1 từ tôi. Chỉ viết cùng một câu trả lời ... – tomafro

+0

được rồi, giả sử rằng việc đặt định dạng trong mô hình là phù hợp hoặc tôi muốn làm điều gì khác ngoài định dạng với mỗi trường ngày trong ứng dụng của tôi, tôi sẽ làm như thế nào? –

+0

vâng, nhưng phần 'start_date' được mã hóa cứng ở đây, tôi cần làm điều này cho tất cả các trường ngày trong ứng dụng, chúng có thể được gọi là start_date, end_date, term_date, finish_date, date, v.v. làm cách nào để kiểm tra phân lớp cho tất cả các cột ngày và sau đó viết một phương thức động cho mỗi cột? –

0

Một câu trả lời cho bình luận của bạn: Bạn có thể trích xuất mã chung/chức năng thành các module mà bạn đưa vào một lớp học (I belive đó được gọi là mixin?) Hoặc bạn có thể đi cho các lớp con. Tôi không nghĩ rằng phân lớp là con đường để đi khi chức năng phổ biến của nó mà bạn muốn nhận được vào các đối tượng của bạn, và không phải là một tình trạng thừa kế thực sự.

Hãy xem this for more info on modules and Ruby.

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