Given a Rails path as a string, add some parameters - ruby-on-rails-3

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.

Related

How to pass parameters in https GET request for (Shopware) Rest API

As far as I understood, GET-Requests encode the parameters throught the url. I want to specify data that I get from the shopware REST-API (https://myshopurl/api/orders).
If I append ?limit=1, that works. But now I want to sort the results first.
The Shopware Rest API documentation says:
$params = [
'sort' => [
['property' => 'name']
]
];
$client->get('articles', $params);
or
$params = [
'sort' => [
['property' => 'orderTime'],
['property' => 'invoiceAmount', 'direction' => 'DESC']
]
];
$client->get('orders', $params);
but I am not sure how to build the URL from this information, because there are parameters within an array. Where do I have to write down the "sort" and do I have to use some brackets?
I hope somebody can help me :)
You simply need to put the filter in the url. Here is an example:
http://mydomain/api/orders?filter[0][property]=customer.email&filter[0][value]=my#domain.de
This is the exact example from here: https://developers.shopware.com/developers-guide/rest-api/#filter,-sort,-limit,-offset

Getting 'undefined method batch' for Google Directory API with service account

So I'm writing a script to batch delete users from a Google Apps for Education domain. The code looks like this:
#! /usr/bin/env ruby
require 'google/api_client'
require 'csv'
service_account_email = 'XXXXXXX#developer.gserviceaccount.com'
key_file = 'key.p12'
key_secret = 'notasecret'
admin_email = 'XXX#xxx'
# Build the API Client object
client = Google::APIClient.new(
:application_name => 'XXX',
:application_version => '0.1'
)
key = Google::APIClient::KeyUtils.load_from_pkcs12(key_file, key_secret)
client.authorization = Signet::OAuth2::Client.new(
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
:audience => 'https://accounts.google.com/o/oauth2/token',
:scope => 'https://www.googleapis.com/auth/admin.directory.user',
:issuer => service_account_email,
:signing_key => key,
:person => admin_email,
)
client.authorization.fetch_access_token!
directory = client.discovered_api('admin', 'directory_v1')
# Reads and parses CSV input into a hash
# Takes file path as an argument
def import_csv(file)
csv = CSV.new(
File.open(file).read,
:headers => true,
:header_converters => :symbol
)
return csv.to_a.map {|row| row.to_hash}
end
users_to_delete = import_csv('accounts.csv')
puts 'Preparing to delete users...'
users_to_delete.each_slice(1000) do |chunk|
directory.batch do |directory|
chunk.each do |user|
client.execute!(
:api_method => directory.users.delete,
:parameters => { :userKey => user[:emailaddress].downcase }
)
end
end
end
puts 'Users successfully deleted!'
When I run the script without the two outer batch blocks, the script runs perfectly (although incredibly slowly).
What I want to know is what I need to change to stop giving me the undefined method error on the 'batch' method for the directory API. In examples in Google's documentation, I've noticed that they call the API differently (zoo = Google::Apis::ZooV1::ZooService.new instead of zoo = client.discovered_api('zoo', 'v1')). I don't see how that would make a difference though.
You can do achieve it this way:
client = Google::APIClient.new(
:application_name => 'XXX',
:application_version => '0.1'
)
directory = client.discovered_api('admin', 'directory_v1')
batch = Google::APIClient::BatchRequest.new do |result|
puts result.data
end
batch.add(:api_method => directory.users.delete,:parameters => { :userKey => user[:emailaddress].downcase })
client.execute(batch)

Why rack/test is combining hashes into one when performing POST or PUT operations

In my rspec test, I defined the following array of hashes and performed a POST:
body = {:event => { :invitations_attributes =>
[ {:recipient_id => 40}, {:email => 'a#a.com'}, {:facebook_id => 123456789} ] } }
post "#{#url}.json", body.reverse_merge(:auth_token => #token)
Based on the above, I expected the Rails server to receive "invitations_attributes" as an array of hashes. However, the developer.log file has the following:
Parameters: {"auth_token"=>"RSySKfN2L8b5QPqnfGf7", "event"=>{"invitations_attributes"=>
[{"recipient_id"=>"40", "email"=>"a#a.com", "facebook_id"=>"123456789"}]}}
(In the parameters above, "invitation_attributes" array contains only 1 hash.)
The following curl statement:
curl -X POST -H "Content-type: application/json" http://localhost:3000/api/v1/events.json -d '{"auth_token":"RSySKfN2L8b5QPqnfGf7","event":{"invitation_attributes":[{"recipient_id":40},{"email":"a#a.com"},{"facebook_id":123456789}]}}'
results in Rails' receiving the array of hashes intact, as evidenced by the log file entry below.
Parameters: {"auth_token"=>"RSySKfN2L8b5QPqnfGf7", "event"=>{"invitation_attributes"=>
[{"recipient_id"=>40}, {"email"=>"a#a.com"}, {"facebook_id"=>123456789}]}}
Rack/test is exhibiting this behavior for PUT operations as well as POST.
Why is rack/test combining the 3 hashes into 1 rather than sending the array exactly as it is defined? Is there a setting which will cause rack to exhibit the behavior I expected?
One workaround is to ensure that each hash contains each key by inserting nil value placeholder keys as follows:
body = {:event => { :invitations_attributes => [
{:recipient_id => 40, :recipient_email => nil, :recipient_facebook_id => nil},
{:recipient_email => user.email, :recipient_id => nil, :recipient_facebook_id => nil},
{:recipient_facebook_id => new_unused_facebook_id, :recipient_email => nil, :recipient_id => nil} ] } }
The hash above does cause the server to receive 3 separate hashes within the array. However, inserting placeholder keys is inconvenient and should not be required. Furthermore, scenarios where a controller acts differently based on the presence of a such a key (albeit uncommon), cannot be tested.

How to order resources from a specific module?

I got some trouble ordering resources from a module.
class { 'postgres' :
charset => 'UTF8',
locale => 'fr_FR',
require => Service['postgresqld'],
}->
class { 'postgresql::server':
}
postgresql::role { 'role1' :
namevar => 'redmine',
password_hash => 'random_md5',
createdb => true,
require => Class['postgres'],
}
postgresql::database_user {'charly':
password => 'random',
role => 'redmine',
require => postgresql::role['role1'],
}
I want to order this, but it appears to have a syntax error on the last line at role.
I'm pretty sure it comes from the capitalized first letter. But Puppet doesn't want to run the manifest if I put a capital letter Postgresql::role['role1] or postgresql::Role['role1]. Without capital letter, I "just" get a warning :
warning: Deprecation notice: Resource references should now be capitalized on line 61 in file /home/charly/testManifests/part1.pp
I'm doing something wrong, but I don't know what. I searched for an answer on the Internet but can't find what I want neither in tutorials nor on the forums.
Try using chaining arrows to your resource group references e.g.
Class['postgres'] -> Class['postgresql::server']
class { 'postgres' :
charset => 'UTF8',
locale => 'fr_FR',
require => Service['postgresqld']
}
class { 'postgresql::server': }
More detail can be found here in the puppet reference Chaining Arrows

OR query matching nil or "" with Mongoid still matches ""?

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.