重构!如何在数据库查询中重新使用变量来检索 Rails 控制器中的数据
Refactoring! How to Re-Use a Variable in Database Query to retrieve data in Rails controller
我正在尝试重构我的railsAPI中的代码,它发送图表的分析数据(它目前正在工作)。因为我在 1. 书签,2. 期刊,3. 目标上执行了相同的代码,所以它不是很枯燥。
我正在尝试创建 1 个可以接收类型(书签、目标、日志)作为参数的数据库查询(使用 PostgreSQL)...我尝试使用 [:type] 和硬编码“类型”,其中书签曾经去例如...
我要重构的现有(工作)代码:
class AnalyticsController < ApplicationController
before_action :authenticate_user
def entries_by_date
bookmarks = current_user.bookmarks.group_by_day(
:created_at,
format: '%Y-%m-%d',
range: 4.weeks.ago.midnight..Time.zone.now
).count
journals = current_user.journals.group_by_day(
:created_at,
format: '%Y-%m-%d',
range: 4.weeks.ago.midnight..Time.zone.now
).count
goals = current_user.goals.group_by_day(
:created_at,
format: '%Y-%m-%d',
range: 4.weeks.ago.midnight..Time.zone.now
).count
entries_array = []
entries_array.push(@bookmarks)
entries_array.push(goals)
entries_array.push(journals)
total_entries_by_date = entries_array.inject { |memo, el| memo.merge(el) { |_k, old_v, new_v| old_v + new_v } }
render json: {
total_entries_by_date: total_entries_by_date,
bookmarks: bookmarks,
goals: goals,
journals: journals
}
end
end
我试过这个:
....
def entries_by_date
def fetch_activity(type)
current_user[:type].group_by_day(
:created_at,
format: '%Y-%m-%d',
range: 4.weeks.ago.midnight..Time.zone.now
).count
end
@bookmarks = fetch_activity(bookmarks)
@goals = fetch_activity(goals)
@journals = fetch_activity(journals)
... (cont'd)
我试过current_user.type... >> 未定义的局部变量或方法`bookmarks
我试过 current_user.[:type]... >> "语法错误,未知 ["
我试过current_user[:type]... >> NameError(未定义的局部变量或方法`bookmarks'
我试过current_user.%{type}... & current_user.#{type}... & current_user.${type}
任何指导将不胜感激 :) 我是 Ruby on Rails 世界的新手,期待在我更好地理解重新使用传递给数据库查询的变量
您已经非常接近解决方案了。只需使用 public_send
并将要调用的方法的名称作为字符串或符号传递。
def entries_by_date
@bookmarks = fetch_activity(:bookmarks)
@goals = fetch_activity(:goals)
@journals = fetch_activity(:journals)
# ...
end
private
def fetch_activity(type)
current_user.public_send(type).group_by_day(
:created_at,
format: '%Y-%m-%d',
range: 4.weeks.ago.midnight..Time.zone.now
).count
end
@bookmarks = fetch_activity(bookmarks)
@goals = fetch_activity(goals)
@journals = fetch_activity(journals)
为了改进 Spickerman 的回答 - 您应该考虑从控制器中提取业务逻辑并将其放置在它所属的模型中:
class User < ApplicationRecord
# Gets a single activity
def fetch_activity(type)
public_send(type).group_by_day(
:created_at,
format: '%Y-%m-%d',
range: 4.weeks.ago.midnight..Time.zone.now
).count
end
# Gets a hash containing the counts of the users activities and total
def fetch_activities(*types)
types.each_with_object({}) do |key, hash|
hash[key] = fetch_activity(key)
end.then do |hash|
hash.merge(total_entries_by_date: hash.values.sum)
end
end
# ...
end
模型比控制器更容易测试,因为您只需设置它并直接在对象上调用方法,而不是通过 HTTP 并解析响应 - 这是您的控制器应该如此瘦的关键原因尽可能:
class AnalyticsController < ApplicationController
before_action :authenticate_user
def entries_by_date
render json: current_user.fetch_activities(:bookmarks, :goals, :journals)
end
end
我正在尝试重构我的railsAPI中的代码,它发送图表的分析数据(它目前正在工作)。因为我在 1. 书签,2. 期刊,3. 目标上执行了相同的代码,所以它不是很枯燥。
我正在尝试创建 1 个可以接收类型(书签、目标、日志)作为参数的数据库查询(使用 PostgreSQL)...我尝试使用 [:type] 和硬编码“类型”,其中书签曾经去例如...
我要重构的现有(工作)代码:
class AnalyticsController < ApplicationController
before_action :authenticate_user
def entries_by_date
bookmarks = current_user.bookmarks.group_by_day(
:created_at,
format: '%Y-%m-%d',
range: 4.weeks.ago.midnight..Time.zone.now
).count
journals = current_user.journals.group_by_day(
:created_at,
format: '%Y-%m-%d',
range: 4.weeks.ago.midnight..Time.zone.now
).count
goals = current_user.goals.group_by_day(
:created_at,
format: '%Y-%m-%d',
range: 4.weeks.ago.midnight..Time.zone.now
).count
entries_array = []
entries_array.push(@bookmarks)
entries_array.push(goals)
entries_array.push(journals)
total_entries_by_date = entries_array.inject { |memo, el| memo.merge(el) { |_k, old_v, new_v| old_v + new_v } }
render json: {
total_entries_by_date: total_entries_by_date,
bookmarks: bookmarks,
goals: goals,
journals: journals
}
end
end
我试过这个:
....
def entries_by_date
def fetch_activity(type)
current_user[:type].group_by_day(
:created_at,
format: '%Y-%m-%d',
range: 4.weeks.ago.midnight..Time.zone.now
).count
end
@bookmarks = fetch_activity(bookmarks)
@goals = fetch_activity(goals)
@journals = fetch_activity(journals)
... (cont'd)
我试过current_user.type... >> 未定义的局部变量或方法`bookmarks
我试过 current_user.[:type]... >> "语法错误,未知 ["
我试过current_user[:type]... >> NameError(未定义的局部变量或方法`bookmarks'
我试过current_user.%{type}... & current_user.#{type}... & current_user.${type}
任何指导将不胜感激 :) 我是 Ruby on Rails 世界的新手,期待在我更好地理解重新使用传递给数据库查询的变量
您已经非常接近解决方案了。只需使用 public_send
并将要调用的方法的名称作为字符串或符号传递。
def entries_by_date
@bookmarks = fetch_activity(:bookmarks)
@goals = fetch_activity(:goals)
@journals = fetch_activity(:journals)
# ...
end
private
def fetch_activity(type)
current_user.public_send(type).group_by_day(
:created_at,
format: '%Y-%m-%d',
range: 4.weeks.ago.midnight..Time.zone.now
).count
end
@bookmarks = fetch_activity(bookmarks)
@goals = fetch_activity(goals)
@journals = fetch_activity(journals)
为了改进 Spickerman 的回答 - 您应该考虑从控制器中提取业务逻辑并将其放置在它所属的模型中:
class User < ApplicationRecord
# Gets a single activity
def fetch_activity(type)
public_send(type).group_by_day(
:created_at,
format: '%Y-%m-%d',
range: 4.weeks.ago.midnight..Time.zone.now
).count
end
# Gets a hash containing the counts of the users activities and total
def fetch_activities(*types)
types.each_with_object({}) do |key, hash|
hash[key] = fetch_activity(key)
end.then do |hash|
hash.merge(total_entries_by_date: hash.values.sum)
end
end
# ...
end
模型比控制器更容易测试,因为您只需设置它并直接在对象上调用方法,而不是通过 HTTP 并解析响应 - 这是您的控制器应该如此瘦的关键原因尽可能:
class AnalyticsController < ApplicationController
before_action :authenticate_user
def entries_by_date
render json: current_user.fetch_activities(:bookmarks, :goals, :journals)
end
end