2012-08-01 13 views
2

我使用Rails 2.3.14如果model在深名稱空間中,set_table_name不起作用 - 在rails 2.3.14中的錯誤?

更新3我在更新2中招只適用於該協會的第一次訪問......所以,我堅持我的應用程序控制器的set_table_name線。這太奇怪了。我希望這得到修復。 = \

UPDATE 2如果我手動/ nastily/hackily爲環境文件底部的麻煩類別設置表格,我不會收到錯誤。

應用程序/配置/ environment.rb中:

Page::Template::Content.set_table_name "template_page_contents" 
Page::Template::Section.set_table_name "template_page_sections" 

爲什麼我必須這樣做?對於這個特殊的用例,軌道是否被打破?

UPDATE:看起來set_table_name在我的Page :: Template :: Content類中最初被調用時不起作用。

,但如果我把它之前,我使用的關聯,它的工作原理...

ap Page::Template::Content.table_name # prints "contents" 
Page::Template::Content.set_table_name "template_page_contents" 
ap Page::Template::Content.table_name # prints "template_page_contents" 

return self.page_template_contents.first # doesn't error after the above is exec'd 

原題

TL; DR:我嘗試訪問has_many關係,但Rails認爲has_many關係使用的表是不同的表

我一直在收到此錯誤,當我嘗試訪問Page::Template::Content通過has_many關係屬於Page::Template

Mysql2::Error: Unknown column 'contents.template_page_id' in 'where clause': SELECT * FROM `contents` WHERE (`contents`.template_page_id = 17) LIMIT 1 

望着錯誤日誌,我想我需要使用一些打印語句,找出原因軌試圖找到錯誤的表關聯的對象開始。

gems_path/activerecord-2.3.14/lib/active_record/associations/association_collection.rb:63:in `find' 

我決定打印@reflection對象,因爲一切似乎都圍繞着要發生的事情。這裏是我是怎麼做的:

require "awesome_print" # best console printer (colors, pretty print, etc) 
    def find(*args) # preexisting method header 
    ap "-------" # separator so I know when one reflection begins/ends, etc 
    ap @reflection # object in question 
    ... # rest of the method 

末「@reflection」的錯誤之前打印:

"-------" 
#<ActiveRecord::Reflection::AssociationReflection:0x108d028a8 
    @collection = true, 
    attr_reader :active_record = class Page::Template < LibraryItem {...}, 
    attr_reader :class_name = "Page::Template::Content", 
    attr_reader :klass = class Content < LibraryItem {...}, 
    attr_reader :macro = :has_many, 
    attr_reader :name = :page_template_contents, 
    attr_reader :options = { 
     :foreign_key => "template_page_id", 
     :class_name => "Page::Template::Content", 
      :extend => [] 
    }, 
    attr_reader :primary_key_name = "template_page_id", 
    attr_reader :quoted_table_name = "`contents`" 
> 

有幾件事情錯在上面的代碼塊。

:klass should be Page::Template::Content 
:name should be :contents 
:quoted_table_name should be `contents` 

我的模型是如何設置:

應用程序/模型/ page.rb:

class Page < LibrayItem 
    belongs_to :template_page, :class_name => "Page::Template" 

應用程序/模型/頁/ template.rb

class Page::Template < Library Item 
    set_table_name "template_pages" 
    has_many :page_template_contents, 
    :class_name => "Page::Template::Content", 
    :foreign_key => "template_page_id" 

應用/模型/網頁/模板/內容。RB

class Page::Template::Content 
    set_table_name "template_page_contents" 
    belongs_to :template_page, 
    :class_name => "Page::Template", 
    :foreign_key => "template_page_id" 



class Page::Template 
... 
    return self.page_template_contents.first 

的關聯選擇類(無關的我的網頁/模板結構以上):

class Content < LibraryItem 
    set_table_name "contents" 
# no associations to above classes 

那麼......是什麼原因造成這一點,我該如何解決?

回答

5

你的問題是不是由於set_table_name而是Rails的是如何找到在具有關聯關係的對象模型類和你有一個頂級型號的事實(內容),它分享它的名字與模型由於嵌套在更深的命名空間中(Page :: Template :: Content)。行爲的奇怪差異很可能是由於在關聯檢查時實際加載的類的差異(請記住,默認情況下,在開發模式下,Rails會在第一次引用時按需加載模型類)。

當你定義一個關聯(不管你是否已經完成指定了關聯的目標模型的類名,或者接受了默認值),Rails必須將目標模型類的名稱變成一個Ruby常量,它可以指向那個目標類。爲此,它調用正在定義關聯的模型類上的受保護類方法compute_type

例如,你有

class Page::Template < LibraryItem 
    set_table_name "template_pages" 
    has_many :page_template_contents, 
    :class_name => "Page::Template::Content", 
    :foreign_key => "template_page_id" 
end 

您可以在Rails的測試控制檯如何compute_type作品該類:

$ ./script/console 
Loading development environment (Rails 2.3.14) 
> Page::Template.send(:compute_type, "Page::Template::Content") 
=> Page::Template::Content(id: integer, template_page_id: integer) 

我看到的結果是,如我所料,一參考類Page :: Template :: Content。但是,如果我重新啓動Rails控制檯,但這次導致模型類內容先被加載(通過引用它),然後再試一次,我看到了這一點(我沒有打擾創建一個表爲內容模式,但這並不改變顯著行爲):

$ ./script/console 
Loading development environment (Rails 2.3.14) 
>> Content # Reference Content class so that it gets loaded 
=> Content(Table doesn't exist) 
>> Page::Template.send(:compute_type, "Page::Template::Content") 
=> Content(Table doesn't exist) 

正如你可以看到,這一次我得到內容,而不是一個參考。

那麼你能做些什麼呢?那麼,首先,你應該認識到,在Rails中使用名稱空間模型類(當然在2.3中)是一個真正的痛苦。在層次結構中組織模型類很好,但它確實會讓生活變得更加困難。正如你上面看到的,如果你在一個命名空間中有一個類與另一個命名空間中的類具有相同名稱,那麼這會變得更加多毛。

如果你仍然希望生活在這種情況下,我可以提出一些建議。下列其中一項可能會有所幫助:

  1. 打開開發模式下的類緩存。這將導致所有模型類都被預加載,而不是像默認那樣按需加載它們。它會讓你的代碼更具可預測性,但可能會使開發有些不愉快(因爲類將不再被每個請求重新加載)。

  2. 明確性要求有問題關聯的類中的依賴類。例如:

    class Page::Template < LibraryItem   
        require 'page/template/content' 
        set_table_name "template_pages" 
        has_many :page_template_contents, ... 
    end 
    
  3. 重寫類的compute_type方法,其中你知道引用相關類可能走歪,使其返回命名空間的類不管是什麼。不知道你的類層次結構中更詳細,我不能就如何做到這一點的完整的建議,但一個快速和骯髒的例子如下:

    class Page::Template < LibraryItem 
        set_table_name "template_pages" 
        has_many :page_template_contents, 
        :class_name => "Page::Template::Content", 
        :foreign_key => "template_page_id" 
    
        def self.compute_type(type_name) 
        return Page::Template::Content if type_name == "Page::Template::Content" 
        super 
        end 
    end 
    
+0

這是很透徹!謝謝! = d – NullVoxPopuli 2012-08-12 18:13:21

相關問題