为什么我的 Rails 5 应用程序每条记录打印两次?
Why does my Rails 5 application print twice each record?
这是一个 rails 管理应用程序,同时也是一个 API。当我调用 myroot/api/v1/users 我得到每条记录两次。
这是我的用户模型class:
class User < ActiveRecord::Base
devise :database_authenticatable, :recoverable,
:trackable, :validatable, :registerable,
:omniauthable
include DeviseTokenAuth::Concerns::User
has_many :records
end
这是我的记录模型class:
class Record < ApplicationRecord
belongs_to :user
has_attached_file :audio,
:url => "/assets/:class/:id/:attachment/:style.:extension",
:path => ":rails_root/public/assets/records/:id/:style/:basename.:extension"
validates_attachment_presence :audio
validates_attachment_size :audio, :less_than => 3.megabytes
validates_attachment_content_type :audio, :content_type => [ 'audio/mpeg', 'audio/mp3' ]
end
这是我的控制器用户 class:
class Api::UsersController < Api::ApiController
before_action :set_user, only: [:show, :edit, :update, :destroy]
def index
# users = User.all
# render json: users.to_json(except: [:id, :user_id, :email, :nickname])
users = User.joins(:records)
render json: users.to_json(only: [:id, :user_id, :email, :nickname],
include: {records: {only: [:record_id, :geolocation, :audio_file_name, :audio_content_type]}})
end
def show
user = User.find(params[:id])
render json: user.to_json(except: [:id, :user_id, :email, :nickname])
end
end
这是 JSON 结果:
[
{
"id": 4,
"nickname": null,
"email": "ricardope@gmail.com",
"records": [
{
"geolocation": "-12.0858307,-76.9795114,17",
"audio_file_name": "StarCraft_2_-_Probe_Quotes.mp3",
"audio_content_type": "audio/mpeg"
},
{
"geolocation": "-12.0858307,-76.9795114,17",
"audio_file_name": "StarCraft_2_-_Selendis_Quotes.mp3",
"audio_content_type": "audio/mpeg"
}
]
},
{
"id": 4,
"nickname": null,
"email": "ricardope@gmail.com",
"records": [
{
"geolocation": "-12.0858307,-76.9795114,17",
"audio_file_name": "StarCraft_2_-_Probe_Quotes.mp3",
"audio_content_type": "audio/mpeg"
},
{
"geolocation": "-12.0858307,-76.9795114,17",
"audio_file_name": "StarCraft_2_-_Selendis_Quotes.mp3",
"audio_content_type": "audio/mpeg"
}
]
},
{
"id": 6,
"nickname": null,
"email": "gabriela@gmail.com",
"records": [
{
"geolocation": "-12.0858307,-76.9795114,17",
"audio_file_name": "StarCraft_2_-_Carrier_Quotes.mp3",
"audio_content_type": "audio/mpeg"
},
{
"geolocation": "-12.0858307,-76.9795114,17",
"audio_file_name": "StarCraft_2_-_Zealot_Quotes.mp3",
"audio_content_type": "audio/mpeg"
}
]
},
{
"id": 6,
"nickname": null,
"email": "gabriela@gmail.com",
"records": [
{
"geolocation": "-12.0858307,-76.9795114,17",
"audio_file_name": "StarCraft_2_-_Carrier_Quotes.mp3",
"audio_content_type": "audio/mpeg"
},
{
"geolocation": "-12.0858307,-76.9795114,17",
"audio_file_name": "StarCraft_2_-_Zealot_Quotes.mp3",
"audio_content_type": "audio/mpeg"
}
]
}
]
这是日志:
Processing by Api::UsersController#index as */*
User Load (0.2ms) SELECT `users`.* FROM `users` INNER JOIN `records` ON `records`.`user_id` = `users`.`id`
Record Load (0.2ms) SELECT `records`.* FROM `records` WHERE `records`.`user_id` = 4
CACHE Record Load (0.0ms) SELECT `records`.* FROM `records` WHERE `records`.`user_id` = 4 [["user_id", 4]]
Record Load (0.3ms) SELECT `records`.* FROM `records` WHERE `records`.`user_id` = 6
CACHE Record Load (0.0ms) SELECT `records`.* FROM `records` WHERE `records`.`user_id` = 6 [["user_id", 6]]
Completed 200 OK in 97ms (Views: 0.3ms | ActiveRecord: 3.4ms)
正如 Pavan 所说,我更改了 users = User.joins(:records) for users = User.all
或 User.includes(:records)
并起作用了。
说明
users = User.joins(:records)
上面的活动记录查询触发 users
和 records
table 之间的 INNER JOIN
查询。这意味着它将从两个 table 中获取所有记录,因为没有 where
子句。
输出将是来自 users
table 或 records
table 的总行数,哪个最高。
这就是您获得 users
table.
重复记录的原因
这一行User.all
只给你users
table行的记录,如果你还想要records
table行那么你必须按照下面。
现在下面的行为您提供 users
table 的结果以及来自 records
table
的所有相关记录
User.includes(:records)
您不会看到来自 users
table 的重复记录。
因为它将在 2 table 秒上查询,一个在 users
上查询,另一个在 records
上查询
希望你能通过这篇post得到更多的说明。
这是一个 rails 管理应用程序,同时也是一个 API。当我调用 myroot/api/v1/users 我得到每条记录两次。
这是我的用户模型class:
class User < ActiveRecord::Base
devise :database_authenticatable, :recoverable,
:trackable, :validatable, :registerable,
:omniauthable
include DeviseTokenAuth::Concerns::User
has_many :records
end
这是我的记录模型class:
class Record < ApplicationRecord
belongs_to :user
has_attached_file :audio,
:url => "/assets/:class/:id/:attachment/:style.:extension",
:path => ":rails_root/public/assets/records/:id/:style/:basename.:extension"
validates_attachment_presence :audio
validates_attachment_size :audio, :less_than => 3.megabytes
validates_attachment_content_type :audio, :content_type => [ 'audio/mpeg', 'audio/mp3' ]
end
这是我的控制器用户 class:
class Api::UsersController < Api::ApiController
before_action :set_user, only: [:show, :edit, :update, :destroy]
def index
# users = User.all
# render json: users.to_json(except: [:id, :user_id, :email, :nickname])
users = User.joins(:records)
render json: users.to_json(only: [:id, :user_id, :email, :nickname],
include: {records: {only: [:record_id, :geolocation, :audio_file_name, :audio_content_type]}})
end
def show
user = User.find(params[:id])
render json: user.to_json(except: [:id, :user_id, :email, :nickname])
end
end
这是 JSON 结果:
[
{
"id": 4,
"nickname": null,
"email": "ricardope@gmail.com",
"records": [
{
"geolocation": "-12.0858307,-76.9795114,17",
"audio_file_name": "StarCraft_2_-_Probe_Quotes.mp3",
"audio_content_type": "audio/mpeg"
},
{
"geolocation": "-12.0858307,-76.9795114,17",
"audio_file_name": "StarCraft_2_-_Selendis_Quotes.mp3",
"audio_content_type": "audio/mpeg"
}
]
},
{
"id": 4,
"nickname": null,
"email": "ricardope@gmail.com",
"records": [
{
"geolocation": "-12.0858307,-76.9795114,17",
"audio_file_name": "StarCraft_2_-_Probe_Quotes.mp3",
"audio_content_type": "audio/mpeg"
},
{
"geolocation": "-12.0858307,-76.9795114,17",
"audio_file_name": "StarCraft_2_-_Selendis_Quotes.mp3",
"audio_content_type": "audio/mpeg"
}
]
},
{
"id": 6,
"nickname": null,
"email": "gabriela@gmail.com",
"records": [
{
"geolocation": "-12.0858307,-76.9795114,17",
"audio_file_name": "StarCraft_2_-_Carrier_Quotes.mp3",
"audio_content_type": "audio/mpeg"
},
{
"geolocation": "-12.0858307,-76.9795114,17",
"audio_file_name": "StarCraft_2_-_Zealot_Quotes.mp3",
"audio_content_type": "audio/mpeg"
}
]
},
{
"id": 6,
"nickname": null,
"email": "gabriela@gmail.com",
"records": [
{
"geolocation": "-12.0858307,-76.9795114,17",
"audio_file_name": "StarCraft_2_-_Carrier_Quotes.mp3",
"audio_content_type": "audio/mpeg"
},
{
"geolocation": "-12.0858307,-76.9795114,17",
"audio_file_name": "StarCraft_2_-_Zealot_Quotes.mp3",
"audio_content_type": "audio/mpeg"
}
]
}
]
这是日志:
Processing by Api::UsersController#index as */*
User Load (0.2ms) SELECT `users`.* FROM `users` INNER JOIN `records` ON `records`.`user_id` = `users`.`id`
Record Load (0.2ms) SELECT `records`.* FROM `records` WHERE `records`.`user_id` = 4
CACHE Record Load (0.0ms) SELECT `records`.* FROM `records` WHERE `records`.`user_id` = 4 [["user_id", 4]]
Record Load (0.3ms) SELECT `records`.* FROM `records` WHERE `records`.`user_id` = 6
CACHE Record Load (0.0ms) SELECT `records`.* FROM `records` WHERE `records`.`user_id` = 6 [["user_id", 6]]
Completed 200 OK in 97ms (Views: 0.3ms | ActiveRecord: 3.4ms)
正如 Pavan 所说,我更改了 users = User.joins(:records) for users = User.all
或 User.includes(:records)
并起作用了。
说明
users = User.joins(:records)
上面的活动记录查询触发 users
和 records
table 之间的 INNER JOIN
查询。这意味着它将从两个 table 中获取所有记录,因为没有 where
子句。
输出将是来自 users
table 或 records
table 的总行数,哪个最高。
这就是您获得 users
table.
这一行User.all
只给你users
table行的记录,如果你还想要records
table行那么你必须按照下面。
现在下面的行为您提供 users
table 的结果以及来自 records
table
User.includes(:records)
您不会看到来自 users
table 的重复记录。
因为它将在 2 table 秒上查询,一个在 users
上查询,另一个在 records
希望你能通过这篇post得到更多的说明。