i am trying to put 2 queries together in a scope - i am unsure where i am going wrong. your advise would be much appreciated
I want to displays only users whose status is stated as "Accepted" or "nil"
i wrote the below scope and tried others but no success
scope :active_recruiters, -> {where(['status = ? OR status = ?', 'Accepted', 'IS NULL'])}
If you want to chain with OR instead of AND user AREL table constraint
scope = where( where(status: 'Accepted').arel.constraints.reduce( :and ).or( where(status: nil).arel.constraints.reduce( :and ) ) )
Try scope :active_recruiters, -> { where(status: ['Accepted', nil]) }
the query that you're trying to curate would look like this:
WHERE status = 'Accepted' OR status = 'IS NULL';
You're probably looking for something like this instead:
WHERE status = 'Accepted' OR status is null;
try this in your code
scope :active_recruiters, -> {where(['status = ? OR status ?', 'Accepted', 'IS NULL'])}
Even better though, how about this?
scope :active_recruiters, -> { where :status, [nil, 'Accepted'] }
Related
I have the following models, which both currently have the same scope:
programme.rb
has_many: :campaigns
scope :visible, -> { where(status: 1) }
camapaign.rb
belongs_to: programme
scope :visible, -> { where(status: 1) }
I would like to edit the campaign scope to only search through the programmes which are visible. Ideally I would like to change that scope to be:
(most likely in a function)
def self.visible
Programme.visible.campaigns.where.(status: 1)
end
But this is returning:
undefined method `campaigns' for #<Programme::ActiveRecord_Relation:0x007f8c9677cd68>
Can someone explain why I can't do this? Also, if any solution to this would be appreciated? preferably without using .joins (But I'll take what I can get at this point)
Thanks
It's hard to tell from your question whether status is an attribute of Programme, Campaign, or both.
Assuming both, you could do this:
# class Programme
has_many :campaigns
scope :visible, -> { where(status: 1) }
# class Campaign
belongs_to :programme
scope :visible, do
joins(:programme).
merge(Programme.visible).
where(status: 1)
end
With this setup, Campaign.visible will only return Campaigns that belong to visible Programmes (and where status == 1, not sure if that means "visible" in your app).
As for why you can't call
Programme.visible.campaigns.where(status: 1)
campaigns is a collection that belongs to a single Programme. It doesn't make sense to ask a collection of Programmes for its campaigns.
I am trying to test some methods within a Domain object, the code seems to execute (based on log) but the assertions fail.
The code being tested (extendDates), is working, I am just adding the unit tests now.
I assume I am doing something wrong in the mocking.The following is a simplified version of my code. Based on the log output, the assertion should pass.
class EventDate{
Date startDate
Date endDate
belongsTo = [Appointments owner]
static constraints = {
endDate(nullable:true, blank:false)
startDate(nullable:false, blank:false)
}
}
class Appointments {
hasMany = [ eventDates: EventDate]
belongsTo = [ customer: Customer ]
def extendDates(start,end){
//some logic on eventDates...
EventDate(startDate:start,endDate:end, owner:this).save(flush:true,failOnError:true);
}
}
#TestFor(Appointments)
#Mock([EventDate])
class AppointmentsTests {
void testDateExtend(){
assertTrue domain != null
assertTrue domain instanceof Appointments
//Log indicates the correct execution and creation of event
domain.extendDates(new Date(),null)
//following returns NullPointerException
assertTrue domain.eventDates.size() == 1
}
}
In your example you test for
if (create_new)
The variable "create_new" is never set and would therefore test false using groovy truth logic, thus never executing the if statement.
The if statement never adds anything to the "eventDates" property of Appointments, this would also mean that the assertion would fail.
I'm thinking your example is incomplete and therefore cannot help you until you expand it.
Yes, you will get NullPointerException in the assert condition. The reason being that, you are creating instance of EventDate in the extendDates method but you are not really adding it to the eventDates list in Appointments domain.
So, you have to modify your that method something like:
// Initialize with empty array to avoid NPE
List<EventDate> eventDates = []
static hasMany = [ eventDates: EventDate]
def extendDates(start, end) {
EventDate instance = EventDate(start, end).save()
// And add it to the list of events
this.addToEventDates(instance)
this.save(flush: true)
}
Now, your test case should work your assert condition.
(Also, looks like you have not added nullable constraint in end but passing the null value while creating instance of EventDate, may be not included in sample code)
I have been using the information here (http://ngauthier.com/2013/08/postgis-and-rails-a-simple-approach.html) so that the search results in my app can be shown based on proximity.
I am listing all tasks with their associated project information - a project can have multiple tasks.
I have the following AR query in my Project controller:
#results = Task.select('tasks.*') # .select('tasks.*') required for pg_search
.joins(:project => :user)
.includes(:project => :user)
.merge(Project.enabled_only.filter_by_location(#geo).search(params[:q]))
.order_results(sort)
In my Project model I have:
scope :distance_from, ->(latitude, longitude) {
select(%{
ST_Distance(
ST_GeographyFromText(
'SRID=4326;POINT(' || projects.longitude || ' ' || projects.latitude || ')'
),
ST_GeographyFromText('SRID=4326;POINT(%f %f)')
) AS distance
} % [longitude, latitude])
}
scope :near, ->(latitude, longitude, distance_in_meters = 1000) {
where(%{
ST_DWithin(
ST_GeographyFromText(
'SRID=4326;POINT(' || projects.longitude || ' ' || projects.latitude || ')'
),
ST_GeographyFromText('SRID=4326;POINT(%f %f)'),
%d
)
} % [longitude, latitude, distance_in_meters])
}
def self.filter_by_location(geo_location)
scoped = self.all
if geo_location.present?
scoped = scoped.distance_from(geo_location[:lat], geo_location[:lng])
scoped = scoped.near(geo_location[:lat], geo_location[:lng])
end
scoped
end
I then have the following in my Task model:
scope :distance_order, -> { order('distance') }
def self.order_results(sort)
# order scopes are appended
scoped = self.all.reorder('')
# check sql for search and distance fields
search_performed = scoped.to_sql.downcase.include?(' pg_search_rank')
distance_calculated = scoped.to_sql.downcase.include?(' distance')
if sort == 'rel'
# rel,dist
scoped = scoped.search_rank_order if search_performed
scoped = scoped.distance_order if distance_calculated
else
# dist,rel
scoped = scoped.distance_order if distance_calculated
scoped = scoped.search_rank_order if search_performed
end
scoped = scoped.name_order
scoped
end
This works fine for my app to sort results by proximity.
Distance is one of the columns in the sql select produced by the AR query, along with tasks.* and distance is being used correctly to sort results but I'm not sure how to display the distance in my view.
If I do <%= result.distance.to_s %>, it says distance is an undefined method. I don't have any joy with <%= result.project.distance.to_s %> either. Whereas <%= result.task_field %> and <%= result.project.project_field %> work fine.
I haven't seen too much use of both .joins() and .includes() at the same time in the RoR world but it did allow me to reduce the number of db calls whilst still producing the correct sql select statement...in my case anyway - that's why they are both used.
Am I missing something?
Is it the complexity of my AR query causing it?
Am I missing something in my Project or Task model to allow the virtual/calculated distance field to be display-able?
Thanks
The complex structure was replaced by a database view.
More details of how to do this can be found at this tutorial (http://pivotallabs.com/database-views-performance-rails/) and in one of my other SO questions here (Connecting database view with polymorphic model in rails).
I am writing Request specs, and having trouble with to test api respond in json formate. I am using capybara and fabricator, here is my code which i trying...
context 'discounts in api' do
let(:user) { Fabricate(:user, activated: true) }
let(:api_token) { user.api_token }
before { visit api_url_for('/v1/discount_coupons', api_token) }
it 'returns coupons collection' do
Fabricate(:discount_coupon, code: 'Discount One', global: true)
save_screenshot("tmp/capybara/screenshot-#{Time::now.strftime('%Y%m%d%H%M%S%N')}.png")
save_and_open_page
expect(json_response['total_records']).to eq 1
expect(json_response['total_pages']).to eq 1
expect(json_response['page']).to eq 0
expect(json_response['discount_coupons'].size).to eq 1
expect(json_response['discount_coupons'][0]['code']).to eq 'Discount One'
end
end
the responce i getting is this
{"discount_coupons":[{"id":11,"code":"Discount One","type":"DiscountPercentage","amount_off":1.5,"global":true,"expires_on":null,"vendors":[]}],"page":0,"total_pages":1,"total_records":1}
and error goes to stop me for run a successful test,
Failure/Error: expect(json_response['total_pages']).to eq 1
NoMethodError:
undefined method `body' for nil:NilClass
I think my expect to json_response is wrong or something missing, can somone help me to do it handsome way please, hint to that how can i test using key and value.
Best way to test an API is use rspec as you just need to do this:
it "should return the expected information" do
get "/url"
parsed_response = JSON.parse(response.body)
expect(parsed_response["key"]).to eq(whatever)
end
it "should update the expected entity" do
post "/url", body, headers
parsed_response = JSON.parse(response.body)
expect(parsed_response["key"]).to eq(whatever)
end
And your tests are failing because you are trying to parse a response that is empty. The Fabric can be failing or the call might be wrong.
I think the issue may be that you are visiting the page in the before block and then generating the discount coupon later on in the assertion block. Try moving the code around like this and see if it yields a better result.
context 'discounts in api' do
let(:user) { Fabricate(:user, activated: true) }
let(:api_token) { user.api_token }
before do
Fabricate(:discount_coupon, code: 'Discount One', global: true)
visit api_url_for('/v1/discount_coupons', api_token)
end
it 'returns coupons collection' do
save_screenshot("tmp/capybara/screenshot-#{Time::now.strftime('%Y%m%d%H%M%S%N')}.png")
save_and_open_page
expect(json_response['total_records']).to eq 1
expect(json_response['total_pages']).to eq 1
expect(json_response['page']).to eq 0
expect(json_response['discount_coupons'].size).to eq 1
expect(json_response['discount_coupons'][0]['code']).to eq 'Discount One'
end
To allow me to quickly filter records in ActiveAdmin i've defined scopes on my model. I have "shipped" and "unshipped" scopes as below. For some reason the "Shipped" scope is working as expected and shows the number of shipped items but the "Unshipped" scope doesn't do anything, it doesn't seem to know what is unshipped. It seems that i have to check and then uncheck "Shipped" checkbox in order for it to know that it's unshipped??
ORDER MODEL
class Order < ActiveRecord::Base
scope :shipped, where(:shipped => true)
scope :unshipped, where(:shipped => false)
end
ADMIN ORDER MODEL
ActiveAdmin.register Order do
scope :all, :default => true
scope :shipped
scope :unshipped
index do
selectable_column
column "Status", :sortable => :shipped do |s|
status_tag((s.shipped? ? "Shipped" : "Unshipped"), (s.shipped? ? :ok : :warning))
end
end
end
Can anyone see what the problem is?
Many Thanks
Is that the actual code from your model?
It should be:
scope :shipped, -> { where(shipped: true) }
scope :unshipped, -> { where(shipped: false) }
Realised that shipped was not by default set to false so fixed the issue by doing so in the Orders table.