Rob Hughes
Rob Hughes

Reputation: 906

Ruby on rails. Sorting my model in a table using scopes and attributes

I've been at this for ages and can't get it right. I have a gig model and a couple of tables. In each table I need to show only gigs that meet certain requirements but there is one table that I cannot figure out.

This table must contain gigs where:

The table must NOT contain gigs where:

my scopes:

scope :expiredr, -> { where('gigzonetime <= ?', Time.current.to_datetime)}
scope :notfilled, -> {where(filled: false)}
scope :filled, -> {where(filled: true)}
scope :expired_and_filled, ->() {self.expiredr.merge(self.filled)}
scope :expired_and_notfilled, ->() { self.expiredr.merge(self.notfilled) }

I have tried loads of variations, eg.

Controller:

def dashboard
    if user_signed_in? && !current_user.try(:artist?)
      @activegigs = current_user.gigs.notcompleted.where.not(:expired_and_notfilled)
      @q = @activegigs.ransack(params[:q])
      @dashgigs = @q.result(distinct: true).order(filled: :desc, reviewed: :desc, date: :asc).page(params[:page]).per(20)
  else
     redirect_to(root_url)
     flash[:danger] = "This page is for registered hosts only"
   end
 end

which gives an

RuntimeError at /gigs/dashboard

unsupported: Symbol

OR

@activegigs = current_user.gigs.notcompleted && current_user.gigs.expired_and_filled && current_user.gigs.notexpired

Which only shows expired_and_filled gigs.

I am not sure how to negate the expired_and_notfilled scope or if that's even necessary. Any suggestions would be appreciated, thanks.

Upvotes: 1

Views: 119

Answers (2)

Andy Gauge
Andy Gauge

Reputation: 1428

OK, so the logic seems to only need to be !expired OR filled. There is no need for the !expired OR (expired and filled) NOT (expired and filled) logic tree. This constructs a simple where query:

.where('gigzonetime > ? OR filled IS TRUE', Time.current.to_datetime)

Upvotes: 1

Jay-Ar Polidario
Jay-Ar Polidario

Reputation: 6603

Using ransack, we need to have an OR condition for not_expired and expired_and_filled to satisfy the table content as you have mentioned.

Add a new scope, and whitelist the two scopes to be filterable by ransack using ransackable_scopes (documentation here)

# gig.rb
scope :not_expired, -> { where('gigzonetime > ?', Time.current.to_datetime) }

def self.ransackable_scopes(auth_object = nil)
  [:not_expired, :expired_and_filled]
end

Now we can combine the query using the advanced ransack using 'OR' instead of the default 'AND' (documentation here)

You need to make sure that

params[:q] == {m: 'or', not_expired: true, expired_and_filled: true }

You can pass m: 'or' through a hidden_field so that params will look like above.

The following should then work properly already.

@q = Gig.ransack(params[:q])
@gigs = @q.result(distinct: true).order(filled: :desc, reviewed: :desc, date: :asc).page(params[:page]).per(20)

@gigs should now include gigs not_expired and gigs expired_and_filled together

Upvotes: 1

Related Questions