RSpec `post` keyword arguments add unwanted key to params - ruby-on-rails

When testing the handling of a callback, the post should return the contents of the body.
I've tried setting it up using the required keyword arguments:
post '/api/v1/callbacks`, body: { foo: 'bar' }
I want the params to be { foo: 'bar' } but they're being returned as { body: { foo: 'bar' } }.
Is there a way I can use the keyword args while not adding the unwanted body key to the params?

There in no body argument, only params
post '/api/v1/callbacks', params: { foo: 'bar' }

In case you want to pass a whole hash as params, instead of having to specify each value, you can do:
post '/post_path', params_hash.merge({:format => 'json'})
See here for more details: https://stackoverflow.com/a/70396862/7724157

Related

How can I build a GQL from a ruby hash?

I am building a rspec helper to test my graphql requests.
So far this is my helper:
def mutation_params(name, attributes:, return_types:)
{
query:
<<~GQL
mutation {
#{name}(
input: { attributes: #{attributes} })
#{return_types}
}
GQL
}
end
and I have to declare the attributes like this:
let(:attributes) do
<<~GQL
{
email: "#{email_param}",
password: "#{password_param}"
}
GQL
end
Now I want to know what I can do to be able to simply pass my arguments as a hash, and have the mutations_params method build the GQL from that hash, by iterating over them.
let(:attributes) do
{
email: email_param,
password: password_param
}
end
Something like:
def mutation_params(name, attributes:, return_types)
gql_attributes = <<~GQL
{
}
GQL
attributes.each do |key, value|
gql_attributes merge with
<<~GQL
"#{key}": "#{value}"
GQL
end
{
query:
<<~GQL
mutation {
#{name}(
input: { attributes: #{gql_attributes} })
#{return_types}
}
GQL
}
end
but that obviously does not work. I think my problem is I don't really understand what that <<~GQL is and how to manipulate it.
You're looking for the squiggly heredoc which was introduced in Ruby 2.3. It's like a normal heredoc but it leaves off leading indentation. https://ruby-doc.org/core-2.5.0/doc/syntax/literals_rdoc.html
So in other words, it's just a string! The GQL bit is arbitrary but a nice way of communicating the purpose of the heredoc.
You could write a helper like this to turn hashes into GraphQL strings
def hash_to_mutation(hash)
attr_gql_str = attributes.map{|k,v| "#{k}: #{v.inspect}"}.join(", ")
" { #{attr_gql_str} } "
end
Then assuming attributes is a hash as in your example you could just
def mutation_params(name, attributes:, return_types:)
{
query:
<<~GQL
mutation {
#{name}(
input: { attributes: #{hash_to_gql(attributes)} })
#{return_types}
}
GQL
}
end

Hash rocket vs colon in render json:

I am rendering a response to a POST request from a webhook. I just realized that when I render json: thingee and I log thingee it has hash rockets which are not valid json.
I've seen where people puts the hash and it looks fine, but that's not what I'm doing, I'm rendering a hash as JSON in response to a POST..
When rendered, my hash looks like this:
{"rates"=>[{"service_name"=>"Standard", "service_code"=>"f48",
"total_price"=>"390",},{"service_name"=>"Expedited", "service_code"=>"f34",
"total_price"=>"640"}]}
But I need it to be valid JSON and look like this:
{"rates":[{"service_name":"Standard", "service_code":"f48",
"total_price":"390",},{"service_name":"Expedited", "service_code":"f34",
"total_price":"640"}]}
Thanks
Don't worry so much. Its perfectly fine.
In Ruby the hashrocket syntax needs to be used whenever you want to have a hash key that is not a symbol:
irb(main):002:0> { foo: 1, 'baz': 2 }
=> {:foo=>1, :baz=>2} # coerces 'baz' into a symbol
irb(main):003:0> { foo: 1, 'baz' => 2 }
=> {:foo=>1, "baz"=>2}
However when you pass the hash render: { json: #foo } the hash is passed to JSON.generate which converts the ruby hash to valid JSON.
irb(main):006:0> JSON.generate({ "foo" => 1, "baz" => 2 })
=> "{\"foo\":1,\"baz\":2}"
irb(main):007:0> JSON.generate({ foo: 1, baz: 2 })
=> "{\"foo\":1,\"baz\":2}"
irb(main):008:0> { foo: 1, baz: 2 }.to_json
=> "{\"foo\":1,\"baz\":2}"

Rspec send params to subject

I wrote a small service, which need params: [:search][:area], [:search][:floor] etc.
I write test:
subject { AwesomeService.new(params) }
let(:params) do
{
"search" => {
'area' => object1.area,
'floor' => object1.floor
}
}
end
But my test fails(manually work perfectly). When I debug my service in test mode, params[:search][:floor] is NULL. How can I fix my params in test?
The params object in rails does not care if you look for values in it as symbols or strings:
params[:search][:floor] == params['search']['floor']
A Hash in ruby, though, is different - if you insert strings as keys, you need to query it with strings.
param_hash[:search][:floor] != params['search']['floor']
You stub params as a hash. This means you should either set it with symbols instead of strings, or use HashWithIndifferentAccess.
subject { AwesomeService.new(params) }
let(:params) do
ActiveSupport::HashWithIndifferentAccess.new {
"search" => {
'area' => object1.area,
'floor' => object1.floor
}
}
end

Rspec expect a yield

I have a hash in Rails and one of the values is a yield.
{
key1: 'foo',
key2: lambda { |p| root_path(p) },
}
I am not entirely sure how I can expect key2 to receive this yield
I looked in to yield_control but I am not sure that is what I need.
I want to assert that key2 receives a yield and I also want to assert what that yield returns (root_path(p))
You want to be sure that key2 contains a lambda and you want to test what the lambda returns?
example of a test for a lambda
let(:my_hash) = {
{
key1: 'foo',
key2: lambda { |p| root_path(p) }
}
}
expect(my_hash[:key2].try(:lambda?)).to be true
to test for result
expect(my_hash[:key2].call("foo")) to eq root_path("foo")

undefined method `symbolize_keys!' for #<Array rails 4

In mcs_mailer.rb:
def invite(email,subject,body,attachment_urls)
#attachment_urls= attachment_urls
mandrill_mail(
template: 'group-invite',
subject: subject,
to: email,
html: body,
attachments: [ #attachment_urls.each do |url|
{
content: File.read(url),
name: 'offer.pdf',
type: 'application/pdf'
}
end
])
I am using mandrill_mail in my rails application.I want to send mail with multiple attachments. But getting error in the each loop undefined methodsymbolize_keys!' for #
Try
# [...]
attachments: #attachment_urls.map do |url|
{
# [...]
}
end
Use map to return an array of each block return value.
You get this error because it tries to symbolize_keys! on the first value of :attachments array, which is also an array (Array#each returns the object itself when a block is provided).

Resources