• Ruby on rails开发从头来(五十五) ActiveRecord基础(一对一关联关系)


          一对一关联,或者更正确的说是一对零或一对一关联,是通过外键引用到另外一张表中的至多一条记录实现的,下图描述了orders表和invoices表的关系:

       
       
    Active Record中,要表示这样的关系需要在Order类中添加has_one:Invoice声明,并且同时在Invoice类中添加声明belongs_to:order,事实上,我们可以把这种关联关系看作是相互的,我们可以使Invoice有一个Order,也可以使Order有一个Invoice,不同的是,在将对象存储到数据库时,如果我们给一个对象赋予has_one关联给另一个既存对象,关联的对象将会自动被保存。例如:

    an_invoice = Invoice.new(...)

    order.invoice = an_invoice # invoice gets saved

        如果我们给一个对象赋予belongs_to关联到另一个对象,那么它将不会自动被保存,例如:

    order = Order.new(...)

    an_invoice.order = order # Order will not be saved

       

        还有另外一个不同点,当你给一个对象赋予has_one关联时,如果指向一个既存的子对象,这个既存对象的外键关联将会被移除,也就是清零,如下图:

       

        还有一个危险的地方,如果子记录不能被保存(没有通过验证等)Active Record也不会有抱怨,你也不会得到任何信息来指示该记录没有添加到数据库,所以,我们强烈推荐使用下面的方法:

    invoice = Invoice.new

    # fill in the invoice

    unless invoice.save!

    an_order.invoice = invoice

        因为save!方法在失败的时候会抛出异常,这样我们就知道发生了什么。

     

    belongs_to声明

        belongs_to声明给一个类指定父关联,Active Record约定在这个表中包含有引用到另一个表的外键,父类的名字假定为混合大小写,且单数,外键字段为单数,并且在末尾添加_id,所以,下面的代码:

    class LineItem < ActiveRecord::Base

    belongs_to :product

    belongs_to :invoice_item

    end

        Active Record关联line item到类ProductInvoiceItem,在底层,使用外键product_idinvoice_item_id关联到productsinvoice_items表的id列。也可以像下面这样,给belongs_to一个哈希(hash)

    class LineItem < ActiveRecord::Base

    belongs_to :paid_order,

    :class_name => "Order",

    :foreign_key => "order_id",

    :conditions => "paid_on is not null"

    end

        在上面的代码里,我们创建了一个关联,叫做paid_order,引用了Order类,通过order_id关联,并且paid_on字段不为null,在这种情况下,我们的关联不直接映射到line_items表的单一的列。belongs_to()方法创建了一组实例方法来管理关联,方法名都以关联的名字开头,例如:

    item = LineItem.find(2)

    # item.product is the associated Product object

    puts "Current product is #{item.product.id}"          

    puts item.product.title

    item.product = Product.new(:title => "Advanced Rails",

    :description => "...",

    :image_url => "http://....jpg",

    :price => 34.95,

    :date_available => Time.now)

    item.save!

    puts "New product is #{item.product.id}"

    puts item.product.title

        运行后我们会得到下面的输出:

    Current product is 2

    Programming Ruby

    New product is 37

    Advanced Rails

        我们使用了在LineItem类中生成的方法product()product=(),来访问和更新关联到line item对象上的product对象。在背后,Active Record保存数据库的步调一致,在我们保存line item对象的时候自动保存关联的product对象,并且将具有新的idproduct对象和line item对象关联起来。

        在这种情况下,下面的方法将被生成到line item对象中:

    product(force_reload=false)

    返回关联的product(如果没有关联的对象就返回nil),同时,结果将被缓存,对于相同的查询,将不会到数据库再次执行,除非force_reload参数为true

        product=(obj)

            将指定的对象关联到line item,设置line item对象的外键到product对象的主键,如果product对象还没有保存,那么会在line item对象保存的同时,对product对象进行保存。

        build_product(attributes={})

            使用指定的attribute,构建一个新的product对象,line item对象将链接到该对象,而且,该对象还没有保存。

        Create_product(attributes={})

            和上面的build_product方法基本相同,差别在于product对象会被保存。

     

    has_one声明

        has_one声明指定一个类为声明所在类的子类(这里的子类不是继承的概念,而是与数据库结构相对应的主从关系)has_one定义了一组和belongs_to相同的方法,所以下面的代码:

    class Order < ActiveRecord::Base

    has_one :invoice

    end

        我们可以这样:

    order = Order.new

    invoice = Invoice.new

    if invoice.save

    order.invoice = invoice

    end

        我们也可以通过传递一组参数来改变Active Record的默认行为,例如::class_name:foreign_key:conditions,就和前面介绍belongs_to时的一样,也可以使用:dependent:order

        :dependent的含义是,在从表中的记录不能独立于主表中的记录而存在,也就是说,如果你删除了父记录,而且你定义了:dependent= trueActive Record将自动删除从表中关联的记录。

        :order指定了在记录被返回前,怎样进行排序,我们会在后面关于has_many的内容里详细讨论。

  • 相关阅读:
    学了axure的感受
    axure的功能
    PS的应用
    day15-1 模块
    day14-2 模块详解
    day14-1 模块定义,导入
    day13-1 Json & pickle 数据序列化
    day12-3 内置方法
    day12-2 内置方法
    day12-1 迭代器和生成器
  • 原文地址:https://www.cnblogs.com/dahuzizyd/p/ruby_rails_study_55.html
Copyright © 2020-2023  润新知