简体   繁体   English

理解Rails中与ActiveRecord的关系

[英]Understanding Relational with ActiveRecord in Rails

I understand SQL I understand Database Methodology I understand Rails I don't understand ActiveRecord Relations 我理解SQL我理解数据库方法我理解Rails我不懂ActiveRecord关系

I have three models (simplified) that i created with rails g model and then performed a rake db:migrate with a mysql db. 我有三个模型(简化),我用rails g模型创建,然后执行rake db:使用mysql db进行迁移。

Calendar
id: number
name: string

Event
id: number
title: string

Event_Tag
id: number
event_id
key: string
value: string

How would i perform a query for all events and retrieve all the event_tags for each so that i could build a JSON model with minimal queries? 我如何对所有事件执行查询并检索每个事件的所有event_tags,以便我可以用最少的查询构建JSON模型?

Event
id: number
title: string
tags: [
    <key>:<value>,
    <key>:<value>,
    <key>:<value>,
]

I have tried this: 我试过这个:

events = Event.includes(:event_tag).where("events.calendar_id" => params[:calendar_id])

Which i have seen avoids the N+1 query issue. 我所见,避免了N + 1查询问题。 And it performs 2 queries. 它执行2个查询。

Event Load (47.1ms)  SELECT `events`.* FROM `events`  WHERE `events`.`calendar_id` = 1

EventTag Load (46.3ms)  SELECT `event_tags`.* FROM `event_tags`  WHERE `event_tags`.`event_id` IN (1) 

But when i inspect an event 但是,当我检查一个事件

eventHash = events[0]

i receive 我收到

#<ActiveRecord::Relation [#<Event id: 1, title: "Test", calendar_id: 1, created_at: nil, updated_at: nil>]>

ActiveRecord ActiveRecord的

Although I don't know the behind-the-scenes workings of ActiveRecord, I do know it's what's called an ORM (Object Related Mapping) system (framework for SQL) 虽然我不知道ActiveRecord的幕后工作,但我知道这就是所谓的ORM(对象相关映射)系统 (SQL框架)

This means it gives you a series of methods to call, which it will then translate into the relevant SQL queries ( joins etc) 这意味着它为您提供了一系列调用方法,然后将其转换为相关的SQL查询( joins等)


Associations 协会

ActiveRecord associations are basically glorified join statements - each time you call an object, and then reference its associated data, you will basically be calling two queries to ping two separate data tables. ActiveRecord关联基本上是美化的join语句 - 每次调用一个对象,然后引用它的关联数据,你基本上会调用两个查询来ping两个单独的数据表。

The way AR works is to use the foreign_key AR的工作方式是使用foreign_key

I think your problem is best solved using an association defined in your Event model: 我认为使用Event模型定义的关联可以最好地解决问题:

#app/models/event.rb
Class Event < ActiveRecord::Base
    has_many :tags, class_name: "EventTag"
end
#app/models/event_tag.rb
Class EventTag < ActiveRecord::Base
    belongs_to :event
end

This will allow you to call the following: 这将允许您调用以下内容:

@event = Event.find params[:id]
@event.tags.each do |tag|
   tag.name
   tag.value
end

If this helps, if you comment, I'll see about helping combine the tags into a JSON hash for you, although I'm not sure what you're trying to do with that exactly 如果这有帮助,如果你发表评论,我会看到有关帮助将tags组合成JSON哈希的方法,虽然我不确定你要用的是什么

The includes method in Rails eager loads the relationships into memory for quicker access so the application doesn't do all the N+1 queries. Rails eager中的includes方法将关系加载到内存中以便更快地访问,因此应用程序不会执行所有N + 1查询。

So even though the relation doesn't show up when you inspect the code, if you access it thru the relation (eg event.event_tag.key ) the application doesn't perform additional queries since the data is already present in memory. 因此,即使在检查代码时没有显示关系,如果通过关系(例如event.event_tag.key )访问它,应用程序也不会执行其他查询,因为数据已经存在于内存中。

Here's a really good article explaining eager loading in Rails (discusses includes and other useful methods eager_load and preload and how they're all related): http://blog.arkency.com/2013/12/rails4-preloading/ 这是一篇非常好的文章,解释了Rails中的热切加载(讨论includes和其他有用的方法eager_loadpreload以及它们如何相关): httpeager_load

As far as building the JSON object, it really depends on how you're going about that. 至于构建JSON对象,它实际上取决于你如何处理它。 I'd imagine the most common libraries (eg jbuilder or active_model_serializers) would handle the relations query fine. 我想最常见的库(例如jbuilder或active_model_serializers)会处理关系查询。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM