Rails 使用 fetch 进行缓存
Rails caching using fetch
Rails.cache.fetch(plan_list_cache_key(project), expires_in: EXPIRES_TIME) do
plans = Plan.all.where(is_active: true)
project_plan = project.project_plan
hash_array = []
plans.each do |plan|
plan = plan.attributes
expired = if (plan["id"] == project.plan.id)
(project_plan.end_date.to_date - Date.current).to_i.positive? ? false : true
else
false
end
subscribed = plan["id"] == project.plan.id
hash_array << plan.merge!({is_expired: expired , subscribed: subscribed})
end
hash_array
end
型号:
class Plan < MysqlBase
has_many :project_plans
end
class ProjectPlan < MysqlBase
belongs_to :plan
belongs_to :project
end
class Project < MysqlBase
has_one :project_plan
has_one :plan, :through => :project_plan
end
架构:
create_table "plans", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.string "name"
t.text "description"
t.integer "email_limit"
t.integer "validity"
t.float "unit_price", limit: 24
t.string "currency"
t.integer "base_user_count"
t.boolean "is_renewable"
t.boolean "is_active"
t.boolean "is_free"
t.string "terms"
t.integer "trial_days"
t.boolean "default"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "project_plans", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.integer "plan_id"
t.integer "project_id"
t.datetime "start_date"
t.datetime "end_date"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
回应
{
"status": "OK",
"status_code": 200,
"message": "ok",
"data": {
"plans": [
{
"id": 1,
"name": "Free",
"description": "30 days free trial",
"email_limit": 10000,
"validity": 30,
"unit_price": 0.0,
"currency": "USD",
"base_user_count": 0,
"trial_days": 30,
"is_free": true,
"subscribed": false,
"is_expired": false
},
{
"id": 2,
"name": "Standard",
"description": " for 100 users",
"email_limit": 0,
"validity": 30,
"unit_price": 0.03,
"currency": "USD",
"base_user_count": 100,
"trial_days": 0,
"is_free": false,
"subscribed": true,
"is_expired": false
}
]
}
}
每个项目都有一个单独的 project_plan。计划对所有用户都是一样的。但我要做的是添加两个额外的字段 is_expired & subscribed 和 API response
我正在使用 fetch 在此处缓存我的响应。但这是进行缓存的正确方法吗,因为有一些数据库和逻辑操作
如果这不是正确的方法,这里会发生什么类型的错误?
进行这种缓存的最佳方法是什么?
此处的一个解决方案是加入项目计划 table 和 select 聚合:
SELECT
plans.*,
-- you will get integers since MySQL is a peasant database and does not have real boolean types
COUNT(pp.id) > 0 AS subscribed,
COALESCE(MAX(pp.ends_at) < NOW(), FALSE) AS is_expired
FROM plans
LEFT OUTER JOIN project_plans pp
ON pp.plan_id = plans.id
AND pp.project_id = ?
GROUP BY plans.id
class Plan
def with_statuses_for_project(project)
pp = ProjectPlan.arel_table
j = pp.join(arel_table).on(
pp[:plan_id].eq(arel_table[:id])
.and(
pp[:project_id].eq(project.id)
)
)
.select(
arel_table[Arel.star],
"COUNT(pp.id) > 0 AS subscribed",
"COALESCE(MAX(pp.ends_at) < NOW(), FALSE) AS is_expired"
)
.joins(j.join_sources)
.group(:id)
end
end
Rails.cache.fetch(plan_list_cache_key(project), expires_in: EXPIRES_TIME) do
plans = Plan.all.where(is_active: true)
project_plan = project.project_plan
hash_array = []
plans.each do |plan|
plan = plan.attributes
expired = if (plan["id"] == project.plan.id)
(project_plan.end_date.to_date - Date.current).to_i.positive? ? false : true
else
false
end
subscribed = plan["id"] == project.plan.id
hash_array << plan.merge!({is_expired: expired , subscribed: subscribed})
end
hash_array
end
型号:
class Plan < MysqlBase
has_many :project_plans
end
class ProjectPlan < MysqlBase
belongs_to :plan
belongs_to :project
end
class Project < MysqlBase
has_one :project_plan
has_one :plan, :through => :project_plan
end
架构:
create_table "plans", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.string "name"
t.text "description"
t.integer "email_limit"
t.integer "validity"
t.float "unit_price", limit: 24
t.string "currency"
t.integer "base_user_count"
t.boolean "is_renewable"
t.boolean "is_active"
t.boolean "is_free"
t.string "terms"
t.integer "trial_days"
t.boolean "default"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "project_plans", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.integer "plan_id"
t.integer "project_id"
t.datetime "start_date"
t.datetime "end_date"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
回应
{
"status": "OK",
"status_code": 200,
"message": "ok",
"data": {
"plans": [
{
"id": 1,
"name": "Free",
"description": "30 days free trial",
"email_limit": 10000,
"validity": 30,
"unit_price": 0.0,
"currency": "USD",
"base_user_count": 0,
"trial_days": 30,
"is_free": true,
"subscribed": false,
"is_expired": false
},
{
"id": 2,
"name": "Standard",
"description": " for 100 users",
"email_limit": 0,
"validity": 30,
"unit_price": 0.03,
"currency": "USD",
"base_user_count": 100,
"trial_days": 0,
"is_free": false,
"subscribed": true,
"is_expired": false
}
]
}
}
每个项目都有一个单独的 project_plan。计划对所有用户都是一样的。但我要做的是添加两个额外的字段 is_expired & subscribed 和 API response
我正在使用 fetch 在此处缓存我的响应。但这是进行缓存的正确方法吗,因为有一些数据库和逻辑操作
如果这不是正确的方法,这里会发生什么类型的错误?
进行这种缓存的最佳方法是什么?
此处的一个解决方案是加入项目计划 table 和 select 聚合:
SELECT
plans.*,
-- you will get integers since MySQL is a peasant database and does not have real boolean types
COUNT(pp.id) > 0 AS subscribed,
COALESCE(MAX(pp.ends_at) < NOW(), FALSE) AS is_expired
FROM plans
LEFT OUTER JOIN project_plans pp
ON pp.plan_id = plans.id
AND pp.project_id = ?
GROUP BY plans.id
class Plan
def with_statuses_for_project(project)
pp = ProjectPlan.arel_table
j = pp.join(arel_table).on(
pp[:plan_id].eq(arel_table[:id])
.and(
pp[:project_id].eq(project.id)
)
)
.select(
arel_table[Arel.star],
"COUNT(pp.id) > 0 AS subscribed",
"COALESCE(MAX(pp.ends_at) < NOW(), FALSE) AS is_expired"
)
.joins(j.join_sources)
.group(:id)
end
end