OR query matching nil or "" with Mongoid still matches ""? - ruby-on-rails-3

I'm trying to write a query for an embedded Mongoid::Document which finds any record where the "address" field is neither nil nor "".
Using a combination of the MongoDB documentation, this issue in the Mongoid bug reports, and the Mongoid documentation, I think that something like this should work:
scope :with_address, where("$or" => [{:address => {"$ne" => nil}}, {:address => {"$ne" => ""}}])
When I run this, the selector looks ok:
1.9.2p290 :002 > report.document.records.with_address
=> #<Mongoid::Criteria
selector: {"$or"=>[{:address=>{"$ne"=>nil}}, {:address=>{"$ne"=>""}}]},
options: {},
class: GlobalBoarding::MerchantPrincipal,
embedded: true>
But when I look at the results, they contain an entry with a blank address:
1.9.2p290 :007 > report.document.records.with_address.last
<Record _id: 4f593f245af0501074000122, _type: nil, version: 1, name: "principal contact 3", title: "", dob: nil, address: "", email: "", phone: "", fax: "">
I can't figure out if I'm doing a query wrong, if this is a bug with Mongoid, or if there is some other issue. Does anyone have experience with such a query?

in the end, this is the only way i could find that works to select records where a certain field is not nil and not blank:
scope :with_name, all_of(:name.ne => nil).all_of(:name.ne => "")

I think you're going to chuckle at this.
Neither nil nor "" is the same as saying:
Not nil and not "".
You really mean and, and that can be expressed without $and, using just:
$ne=>nil, $ne=>""

You can do the more succint:
scope :with_name, where(:name.nin => ["", nil])
See MongoDB manual.

Related

API Platform - Get collection where Author is User

I currently have an Offer entity which has an author property, like so :
#[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'offers')]
#[ORM\JoinColumn(nullable: false)]
private $author;
Currently, when I do a get request on /offers/, I get a collection of ALL the offers, which is normal.
I would want to only retrieve the offers where the author is the logged in user instead. (basically a findBy(['author'=>$this->getUser()]))
After searching on the internet I've been trying the following, which obviously is not working
#[ORM\Entity(repositoryClass: OfferRepository::class)]
#[ApiResource(
normalizationContext: [
'groups' => ['read'],
],
itemOperations: [
'get' => [
'security' => 'object.author == user',
]
],
collectionOperations: [
'get' => [
'security' => 'object.author == user',
]
]
)]
class Offer
{
...
This gives me the following error :
hydra:description: "Warning: Undefined property:
ApiPlatform\Core\Bridge\Doctrine\Orm\Paginator::$author"
Which tells me this is completely the wrong approach.
Kind of stuck here, any hint ?
Thank you.
Maybe a bit late but this is answered by implementing an "extension". That would allow the collection to be filtered to match only items with a specific condition (in your case, a User).
There's an old issue (here: https://github.com/api-platform/core/issues/1481).
And official documentation here: https://api-platform.com/docs/core/extensions/#example.

Many-To-Many Association on Same Model using Waterline & Sails.js [duplicate]

I'm pretty new on Nodejs and sails.
I'm implementing a server which is similiar to Twitter. In user model, there should be 2 fields: follower and following, and the 2 fields are association of the model 'user' itself.
My question is when the model have only 1 association, either follower or following, it works.
However, when both follower and following included, there would be en error.
The code is something like this:
module.exports = {
attributes: {
alias: {
type:'string',
required: true,
primaryKey: true
},
pwd: {
type: 'string',
required: true
},
follower: {
collection: 'user',
via: 'alias'
},
following:{
collection: 'user',
via: 'alias'
}
}
The code will cause such error:
usr/local/lib/node_modules/sails/node_modules/waterline/node_modules/waterline-schema/lib/waterline-schema/references.js:115
throw new Error('Trying to associate a collection attribute to a model tha
^
Error: Trying to associate a collection attribute to a model that doesn't have a Foreign Key. user is trying to reference a foreign key in user
at References.findReference (/usr/local/lib/node_modules/sails/node_modules/waterline/node_modules/waterline-schema/lib/waterline-schema/references.js:115:11)
at References.addKeys (/usr/local/lib/node_modules/sails/node_modules/waterline/node_modules/waterline-schema/lib/waterline-schema/references.js:72:22)
For such usage your model definition is incorrect, namely the via keywords. As per the waterline associations docs the via keyword references the other side of the association. So, for a follower the other side is following and vice-versa. In other words:
follower: {
collection: 'user',
via: 'following'
},
following:{
collection: 'user',
via: 'follower'
}
You can check a full working example at: https://github.com/appscot/sails-orientdb/blob/master/test/integration-orientdb/tests/associations/manyToMany.selfReferencing.js

RSpec gives error 'trait not registered: name'

I tried to test my Rails 3 application on Windows with RSpec. I've wrote tests and factories, but can't solve the issues which raise when I run RSpec on command line.
Here is one of the test files:
require 'spec_helper'
describe "SignIns" do
it "can sign in" do
user = FactoryGirl.create(:user)
visit new_user_session_path
fill_in "login", with: user.username
fill_in "password", with: user.password
click_on "sign in"
current_user.username.should == user.username
end
end
And here's the factories.rb:
factory :layout do
name "layout1"
end
factory :club do
sequence(:name) { |i| "Club #{i}" }
contact_name "John Doe"
phone "+358401231234"
email "#{name}#example.com"
association :layout
end
factory :user do
sequence(:username) { |i| "user#{i}" }
password 'password'
email "test#example.com"
club
end
When I try to run RSpec it gives the following error:
trait not registered: name
#C: in 'object'
#.spec/features/sign_in_spec.rb:11:in 'block (2 levels) in (top(required))
What am I doing wrong?
I know this is an old question, but in case anyone else ends up here when searching "Trait not registered":
When using a dependent attribute like how email depends on name in the :club factory from the question, you need to wrap the attribute in curly braces so it gets lazy evaluated:
email {"#{name}#example.com"}
It's a FactoryGirl error, and it seems you're using (at spec/features/sign_in_spec.rb:11) something like :
FactoryGirl.create :user, :name
This will only work if you registered a trait called name for the Factory user, more on traits here
Note that if you just want to override the name of the created user, the syntax is
FactoryGirl.create :user, name: 'THE NAME'
For future readers' reference:
What didn't work -
ArgumentError:
Trait not registered: user_id
FactoryBot.define do
factory :startup do
user_id
name { FFaker::Lorem.word }
website { FFaker::Internet.uri(host: 'example.com') }
founded_at { "01.01.2000" }
end
end
How I solved this issue using either of these, when everything seemed to look right:
put empty curly braces after user_id
FactoryBot.define do
factory :startup do
user_id {}
name { FFaker::Lorem.word }
website { FFaker::Internet.uri(host: 'example.com') }
founded_at { "01.01.2000" }
end
end
Move user_id below other block-using helpers:
FactoryBot.define do
factory :startup do
name { FFaker::Lorem.word }
website { FFaker::Internet.uri(host: 'example.com') }
founded_at { "01.01.2000" }
user_id
end
end
Another late answer. I banged my head awhile because I forgot my model is very new and I didn't migrate the test database. So the attribute in fact did not exist.
i.e. had to run beforehand
rails db:migrate RAILS_ENV=test
In my case, none of the above(below?) answers helped to solve trait not registered error.
This time it was caused by improper order of loading factories. I've moved a file with declared global traits and FactoryBot started to load it in an improper order.
How did I fix it?
Rename it as, "spec/factories/01_factory_traits" and the issue is solved.
Perhaps there is a better way but it works.

Given a Rails path as a string, add some parameters

Given a string containing an arbitrary path:
s = "/api/doctors/123/patients?page=4&active=true"
What's the best way to add another parameter to this path? I'm looking for something with behavior like the following:
merge_parameters s, :foo => 'bar'
# => "/api/doctors/123/patients?page=4&active=true&foo=bar"
merge_parameters s, :page => 5
# => "/api/doctors/123/patients?page=5&active=true"
Does this exist?
What I'm looking to do is to add a next link in my API for pagination, so that clients know how to get the next page of results:
{
"results": [ {...}, {...}, ... ]
"next": "/api/doctors/123/patients?page=5"
}
My hope is that I can use request.path and this method to produce the next page of results.
You can use the URI class for this.
>rails c
Loading development environment (Rails 3.2.6)
1.9.3p194 :001 > a = URI.parse("/api/doctors/123/patients?page=4&active=true")
=> #<URI::Generic:0x007fa27c33f6f0 URL:/api/doctors/123/patients?page=4&active=true>
1.9.3p194 :002 > a.path
=> "/api/doctors/123/patients"
1.9.3p194 :003 > a.query
=> "page=4&active=true"
Split the params into a hash, merge it with new values, hash to string, reassign and then uri to string or variations of.

Filter products with API Magento in Ruby on Rails with Savon gem (SOAP)

I am using this code for my rails app with the API of Magento. Everything is fine except for one thing, i need filter the products by arguments of the Magento API but i don't know how :(
Obviously i have tested with more solutions (array, hash, etc), but
unsuccessful.
Pd: Sorry, my english is very limited
Links
Related case (fail): Adding a product using Savon to connect to Magento API
Example: http://www.polyvision.org/2011/10/02/using-magento-soap-api-with-ruby-and-savon.html
I know this is very late, but if anyone else is finding this thread, I've created a magento_api_wrapper gem that implements filters for the Magento SOAP API v2. You can find the code here: https://github.com/harrisjb/magento_api_wrapper
To summarize, if you want to use one of the Magento SOAP API simple filters, you can pass a hash with a key and value:
api = MagentoApiWrapper::Catalog.new(magento_url: "yourmagentostore.com/index.php", magento_username: "soap_api_username", magento_api_key: "userkey123")
api.product_list(simple_filters: [{key: "status", value: "processing"}, {key: created_at, value: "12/10/2013 12:00" }])
And to use a complex filter, pass a hash with key, operator, and value:
api.product_list(complex_filters: [{key: "status", operator: "eq", value: ["processing", "completed"]}, {key: created_at, operator: "from", value: "12/10/2013" }])
Spent ages getting this to work with Savon - there are no actual solutions on the web. Went and looked at the SOAP call and was missing :item
params = {:filter => {:item => {:key => "status", :value => "closed"}}}
result = client.call(:sales_order_list, message: { session_id: session_id, filters: params})
This will only return orders that are of status closed.
If you are looking to work with Magento and Rails, Gemgento might be what you need. It replaces Magento's front end with RoR.
http://www.gemgento.com
After you sync with Magento you can use the Gemgento::Product.filter method along with some scopes to easily search the EAV structure of Magento.
attribute = Gemgento::Attribute.find_by(code: 'color')
Gemgento::Product.filter({ attribute: attribute, value: 'red' })
The filter method can actually take all sorts of array/hash combos
filters = [
{ attribute: [attribute1, attribute2], value: %w[red yellow black] },
{ attribute: size_attribute, value: 'L' }
]
Gemgento::Product.filter(filters)