3

I come from a Python and Java background with only basic knowledge to CSS, HTML, Ruby and trying to learn web development using Ruby on Rails. I'm trying to follow the tutorial on Michael Hartl. I do not understand what arguments the post method in Listing 7.23 is doing.

require 'test_helper'

class UsersSignupTest < ActionDispatch::IntegrationTest

  test "invalid signup information" do
    get signup_path
    assert_no_difference 'User.count' do
      post users_path, params: { user: { name:  "",
                                         email: "user@invalid",
                                         password:              "foo",
                                         password_confirmation: "bar" } }
    end
    assert_template 'users/new'
  end
end

From what I trace in the API, it takes in 2 non-optional arguments which are both Strings, but in Listing 7.23 there is a sudden hash syntax params: in the 2nd argument and this has confused me. Can anyone enlighten me?

2 Answers 2

5

I think you're looking at the wrong place, the link shows http.post. You want the IntegrationTest post.

From: https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/testing/integration.rb

def post(path, **args)
  process(:post, path, **args)
end

And:

def process(method, path, params: nil, headers: nil, env: nil, xhr: false, as: nil)
  request_encoder = RequestEncoder.encoder(as)
  headers ||= {}

  # rest
end

Edit: The double splat

Ruby 2.0 added the keyword arguments and the double splat. A single splat (*) is basically used when you have an unknown number of arguments, and it is passed as array.

def with_args(*args)
  p args
end

with_args(1,2,"a")
# [1, 2, "a"]

The double splat (**) acts like the *, but for keyword arguments:

def with_args(**args)
  with_keyword(args)
end

def with_keyword(some_key: nil, other_key: nil)
  p "some_key: #{some_key}, other_key: #{other_key}"
end

with_args(some_key: "some_value", other_key: "other_value")
# "some_key: some_value, other_key: other_value"
with_args(some_key: "some_value")
# "some_key: some_value, other_key: "

In ruby, you can call a method without () and pass a hash without {}, so

with_args({some_key: "some_value", other_key: "other_value"})

is like writing

with_args some_key: "some_value", other_key: "other_value")

See this answer: What does a double * (splat) operator do and https://medium.freecodecamp.org/rubys-splat-and-double-splat-operators-ceb753329a78

So...

When writing

post users_path, params: { user: { name:  "",
                                   email: "user@invalid",
                                   password:              "foo",
                                   password_confirmation: "bar" } }

Is calls to process

process(:post, users_path, params: { user: { name:  "",
                                   email: "user@invalid",
                                   password:              "foo",
                                   password_confirmation: "bar" } }

Meaning in process, params are the hash

{ user: { name:  "",
  email: "user@invalid",
  password:              "foo",
  password_confirmation: "bar" } }

It doesn't matter the other keyword args of process, the hash is all params, all the other keywords are nil

Hope it makes sense...

Sign up to request clarification or add additional context in comments.

6 Comments

Hi, would you mind enlightening me how the method call to process works? I have explained some of my thought process in the answer above, but I can't fully grasp it from the tutorial's context.
@PrashinJeevaganth Sure, what I can. I edited the answer with the double splat (**) syntax and how the call is passed to process.
Correct me if I'm wrong. By the assertion, we use the one without the error message, User.count is evaluated twice, once at the start, then a 2nd time after executing the code block, which is the post function that has some hash parameters as mentioned in this answer. post might return something due to process, but may also update the count, so we want the console to sound off "red" when there is actually a difference. Not quite sure what the assert's implementation is doing but that's my best bet.
@PrashinJeevaganth You are mostly correct, the User.count is evaluated twice. But the test is to check that the number stays the same, as it is a post request to create an invalid user. If the post request would update the count, it is a bug and the test should fail. If you will look at the implementation, you'll see that assert_no_difference just calls to assert_difference with 0. The implementation of is: assert_difference. apidock.com/rails/ActiveSupport/Testing/Assertions/…
I'm actually confused by this: post :create, article: invalid_attributes in assert_no_difference , :something usually means that we have defined a hash beforehand and want to access the value of the corresponding key, but where do you find :create since it's a method and not some kind of key? The same confusion for article. I just interpreted it as what you mentioned just by reading the name, but I can't really reason with the code implementation.
|
3

Ah! Great question. This line:

class UsersSignupTest < ActionDispatch::IntegrationTest

means that the class is inheriting from ActionDispatch::IntegrationTest.

ActionDispatch::IntegrationTest is a Rails class. You're looking at the docs for the Net::HTTP class, which is a Ruby class.

Here's the API docs for the ActionDispatch::IntegrationTest methods.

Getting mixed up between Ruby and Rails is very common at the start. Rails is the framework, Ruby is the language.

3 Comments

Hi, thanks for the reply, actually I'm pretty confused by the number of API I have to look into(Rails,Ruby,HTTP,HTML,CSS). Usually I just get stumped at the tutorial and I don't know whether they are overriding an existing class method or they are implementing a new one from nowhere.
Oh, it's much more readable source than my answer, I just looked at github :)
And I actually don't understand the API either as shown in the answer before yours, from my basic understanding I think **args in post(path,**args) does imply the need to pass in a Hash, and the same Hash is being passed into process, but then the problem arises when there are so many keyword arguments in process and I don't see how the key-value pairs that are contained in the Hash are mapped to the arguments.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.