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
Models:
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
Schema:
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
Response
{
"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": "$3 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
}
]
}
}
Each project has a separate project_plan. Plans are the same for all users. But what I have to do is to add two additional fields is_expired & subscribed with the API response
I am caching my response here using fetch. But is it the right way to doing cache as there are some DB & logical operations
If that isn't the right way what type of error can be happened here?
What will be the best approach to do this kind of caching?
CodePudding user response:
One solution here is to join the project plans table and select aggregates:
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