Вопрос

I have the following relationships in the User model.

has_many :subscriptions, dependent: :destroy
has_one :subscription, -> { where 'end_date >= ?', Date.today }

:subscription is essentially their most current monthly subscription. :subscriptions is an array of all their previous monthly subscriptions (including the most current). They list the start_date, end_date, user_id, plan_id, payment_method.

When a subscription plan is upgraded or downgraded, I changed the end_date on the current subscription to Date.today (signifying the subscription ended today) and then create a new subscription that starts today and ends in a month.

The problem with having the end_date as Date.today is that the WHERE clause will pick up the cancelled subscription and the new subscription. But will favor the cancelled subscription because the SQL query generated tacks on the ORDER BY class for primary id ascending.

ORDER BY "subscriptions"."id" ASC LIMIT 1

For the life of me, I can't figure out how to reverse the ORDER BY from ASC to DESC on the id. But I'd much prefer it to order based on the created_at timestamp. The following would be the appropriate code just for ordering, but it's necassary that I have the WHERE clause in addition to the ORDER BY clause.

has_one :subscription, -> { order 'created_at desc' }

Has anyone figured how to combine the two?

Это было полезно?

Решение

As of Rails 4, Rails automatically adds the ordering by id when you call the first method. (You can call take instead to avoid this.) So I'd guess that has_one is calling first internally.

Since has_one is just auto-creating a method called subscription, why not just create it yourself?:

def subscription
  subscriptions.where('end_date >= ?', Date.today).order("created_at DESC").take
end

If you don't like this, it's not clear from your question whether you've tried this:

has_one :subscription, -> { where('end_date >= ?', Date.today).order("created_at DESC") }

There's no reason you can't chain the two items like that. But as I recall the Rails 4 first will override your order directive and replace it with order(:id), so this might not work. You can find out for sure by saying @user.subscription.to_sql.

Другие советы

The problem appears to be a mismatch in your design between expiring subscriptions and dating them as "today", and stating that only one subscription can have an end date >= today. They contradict each other, so you need to resolve that issue.

The heart of it seems to be that subscription start dates are inclusive and end dates are exclusive -- unless you define end dates as being "the last date on which the subscription is active" rather than "the day after the last day on which the subscription is active", you have two subscriptions being active on the same day.

Apart from creating a custom method to handle this, rather than using a has_one relationship, the only solution I could find out on ordering the query is by setting the scope in the Subscription model to order by created_at DESC.

class Subscription < ActiveRecord::Base
  belongs_to :user
  belongs_to :plan

  default_scope order: 'created_at DESC'


  #Subscription Load (0.2ms)  SELECT "subscriptions".* FROM "subscriptions" WHERE "subscriptions"."user_id" = ? AND (end_date >= '2014-01-25') ORDER BY end_date DESC LIMIT 1  [["user_id", 2]]                                                                                                      
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top