2008-11-30 24 views
5

Trong ứng dụng của tôi, một người dùng có_many vé. Thật không may, bảng vé không có user_id: nó có user_login (nó là một cơ sở dữ liệu kế thừa). Tôi sẽ thay đổi một ngày nào đó, nhưng bây giờ thay đổi này sẽ có quá nhiều ý nghĩa.Làm cách nào để chuyển một chuỗi tới tham số has_many: finder_sql?

Vậy làm cách nào tôi có thể tạo liên kết "người dùng has_many: vé" thông qua cột đăng nhập?

Tôi đã thử finder_sql sau, nhưng nó không hoạt động.

class User < ActiveRecord::Base 
    has_many :tickets, 
     :finder_sql => 'select t.* from tickets t where t.user_login=#{login}' 
    ... 
end 

tôi nhận được một lỗi lạ:

ArgumentError: /var/lib/gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:402:in `to_constant_name': Anonymous modules have no name to be referenced by 
    from /var/lib/gems/1.8/gems/activerecord-2.0.2/lib/active_record/base.rb:2355:in `interpolate_sql' 
    from /var/lib/gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:214:in `qualified_name_for' 
    from /var/lib/gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:477:in `const_missing' 
    from (eval):1:in `interpolate_sql' 
    from /var/lib/gems/1.8/gems/activerecord-2.0.2/lib/active_record/associations/association_proxy.rb:95:in `send' 
    from /var/lib/gems/1.8/gems/activerecord-2.0.2/lib/active_record/associations/association_proxy.rb:95:in `interpolate_sql' 
    from /var/lib/gems/1.8/gems/activerecord-2.0.2/lib/active_record/associations/has_many_association.rb:143:in `construct_sql' 
    from /var/lib/gems/1.8/gems/activerecord-2.0.2/lib/active_record/associations/has_many_association.rb:6:in `initialize' 
    from /var/lib/gems/1.8/gems/activerecord-2.0.2/lib/active_record/associations.rb:1032:in `new' 
    from /var/lib/gems/1.8/gems/activerecord-2.0.2/lib/active_record/associations.rb:1032:in `tickets' 
    from (irb):1 

Tôi cũng đã cố gắng finder_sql này (với dấu ngoặc kép quanh đăng nhập):

:finder_sql => 'select t.* from tickets t where t.user_login="#{login}"' 

Nhưng nó không giống như vậy (và dù sao , nếu nó làm việc nó sẽ dễ bị tiêm sql).

Trong một cơ sở dữ liệu kiểm tra, tôi đã thêm một cột user_id trong bảng vé, và cố gắng finder_sql này:

:finder_sql => 'select t.* from tickets t where t.user_login=#{id}' 

Bây giờ này hoạt động tốt. Vì vậy, rõ ràng, vấn đề của tôi đã làm với thực tế là cột người dùng tôi đang cố gắng sử dụng là một chuỗi, không phải là một id.

Tôi đã tìm kiếm trên mạng trong một thời gian khá ... nhưng không thể tìm thấy manh mối.

Tôi rất thích để có thể vượt qua bất kỳ tham số cho finder_sql, và viết những điều như thế này:

has_many :tickets_since_subscription, 
:finder_sql => ['select t.* from tickets t where t.user_login=?'+ 
    ' and t.created_at>=?', '#{login}', '#{subscription_date}'] 

Chỉnh sửa: Tôi có thể không sử dụng: thông số foreign_key của hiệp hội has_many vì người dùng của tôi bảng làm có một cột khóa chính id, được sử dụng ở nơi khác trong ứng dụng.

Chỉnh sửa # 2: dường như tôi không đọc tài liệu đủ kỹ lưỡng: liên kết has_many có thể lấy tham số: primary_key, để chỉ định cột nào là khóa chính cục bộ (id mặc định). Cảm ơn Daniel vì đã mở mắt ra! Tôi đoán nó sẽ trả lời câu hỏi ban đầu của tôi:

has_many tickets, :primary_key="login", :foreign_key="user_login" 

Nhưng tôi vẫn muốn biết cách tôi có thể thực hiện công việc liên kết has_many: ticket_since_subscription.

Trả lời

4

Tôi nghĩ bạn muốn tùy chọn :primary_key thành has_many. Nó cho phép bạn chỉ định cột trên Bảng hiện tại có giá trị được lưu trữ trong cột :foreign_key trên bảng khác.

has_many :tickets, :foreign_key => "user_login", :primary_key => "login" 

Tôi tìm thấy điều này bằng cách đọc tài liệu has_many.

+1

OMG, tôi không thể tin rằng tôi không thấy tùy chọn này khi tôi đọc tài liệu 10 lần! Tôi nghĩ rằng tôi cần một số kỳ nghỉ. Cảm ơn bạn rất nhiều! :-) – MiniQuark

1

Tôi nghĩ bạn đang tìm kiếm tùy chọn :foreign_key trên has_many. Điều đó sẽ cho phép bạn chỉ định rằng khóa ngoại không phải là user_id, nhưng là user_login, mà không điều chỉnh logic của trình tìm kiếm.

Xem tài liệu ActiveRecord has_many để biết thêm chi tiết.

+0

Cảm ơn. Nhưng tôi đã thử điều đó và nó không hoạt động vì cột đăng nhập # người dùng không phải là khóa chính của bảng người dùng. Nó có một khóa chính id. Nó sẽ hoạt động nếu điều này là có thể: : foreign_key => "user_login", **: key => "login" ** Nhưng tham số khóa: không tồn tại. – MiniQuark

0

Chỉ cần trả lời cho chính tôi, trong trường hợp không có giải pháp nào tốt hơn. Tôi không thể tìm thấy một giải pháp với hiệp hội has_many, vì vậy tôi đã tạo ra một phương pháp tìm đơn giản. Không tuyệt vời chút nào: nó cho phép tôi gọi some_user.tickets, nhưng nó không mang lại cho tôi tất cả lợi ích của các hiệp hội has_many (cụ thể là xóa, xóa, < <, ... phương pháp trên chính hiệp hội).

def tickets 
    return Ticket.find(:all, :conditions=>["user_login = ?", login]) 
end 

Tôi vẫn hy vọng rằng ai đó sẽ đưa ra giải pháp tốt hơn.

2

Để có cái gì đó như has_many: tickets_since_subscription bạn có thể sử dụng named_scopes:

Trong mô hình add:

named_scope :since_subscription, lambda { |subscription_date| { :conditions => ['created_at > ?', subscription_date] } 

Với điều này, bạn có thể tìm thấy những gì bạn muốn như thế này:

user.tickets.since_subscription 3.days.ago 

hoặc

user.tickets.since_subscription user.subscription_date 

(tất nhiên bạn cần cột subscription_date trong mô hình người dùng).

Bạn có thể tìm thêm ví dụ here.

Nếu bạn không muốn sử dụng named_scopes bạn có thể tìm thấy những gì bạn muốn với điều này:

user.tickets.all(:conditions => ['created_at > ?', subscription_date]) 
Các vấn đề liên quan