Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Newbie question #255

Closed
kapso opened this issue Feb 8, 2015 · 14 comments
Closed

Newbie question #255

kapso opened this issue Feb 8, 2015 · 14 comments
Assignees
Labels

Comments

@kapso
Copy link

kapso commented Feb 8, 2015

class CreateUser < ActiveInteraction::Base
  hash :user_params, default: {} do
    string :first_name, :last_name
  end

  def execute
    # ...
  end
end

When I run CreateUser.run, I get the following error - ActiveInteraction::InvalidNestedValueError: ActiveInteraction::InvalidNestedValueError

Is this expected behavior? I was hoping to see required validation errors for first_name and last_name

Unfortunately its unclear how Hash filters work.

@OpenCoderX
Copy link

Try with one call to string for each symbol, the example here shows: https://github.com/orgsync/active_interaction#how-do-i-define-an-interaction

class CreateUser < ActiveInteraction::Base
  hash :user_params, default: {} do
    string :first_name
    string :last_name
  end

  def execute
    # ...
  end
end

@tfausak tfausak self-assigned this Feb 9, 2015
@tfausak
Copy link
Collaborator

tfausak commented Feb 9, 2015

Hashes behave differently than other filters when it comes to defaults. Setting default: {} means that the default hash will be constructed using the defaults from the block. Since both of your strings are required, the default hash turns out to be invalid. There are two ways you can fix this:

  1. Change default: {} to default: nil. This makes the hash optional and doesn't try to create a default hash.
  2. Add a default (probably default: '') to your strings. This makes the strings inside the hash optional so it can successfully create the default hash.

Here's how they would look:

require 'active_interaction' # 1.5.0

class CreateUser < ActiveInteraction::Base
  hash :user_params_1, default: nil do
    string :first_name, :last_name
  end

  hash :user_params_2, default: {} do
    string :first_name, :last_name, default: ''
  end

  def execute
    inputs
  end
end

CreateUser.run!
# => {:user_params_1=>nil, :user_params_2=>{:first_name=>"", :last_name=>""}}

@kapso
Copy link
Author

kapso commented Feb 10, 2015

Tried both the approaches, does not work. My requirement is that first_name & last_name are required and they are available inside user_params hash. I am using v1.5.0

@tfausak
Copy link
Collaborator

tfausak commented Feb 10, 2015

If that's the case, you don't want a default value for the hash at all.

class CreateUser < ActiveInteraction::Base
  hash :user_params do
    string :first_name, :last_name
  end

  def execute
    inputs
  end
end

CreateUser.run!
# ActiveInteraction::InvalidInteractionError: User params is required
CreateUser.run!(user_params: {})
# ActiveInteraction::InvalidInteractionError: User params has an invalid nested value ("first_name" => nil)
CreateUser.run!(user_params: { first_name: 'Jane' })
# ActiveInteraction::InvalidInteractionError: User params has an invalid nested value ("last_name" => nil)
CreateUser.run!(user_params: { first_name: 'Jane', last_name: 'Doe' })
# => {:user_params=>{:first_name=>"Jane", :last_name=>"Doe"}}

@kapso
Copy link
Author

kapso commented Feb 10, 2015

@tfausak Thanks. Yea those errors are a little weird, why not show "is required" message for hash params - first & last name?

@tfausak
Copy link
Collaborator

tfausak commented Feb 10, 2015

That is a great question! Nested error messages used to be misleading (#36). We made them better (#158), but it looks like they could be better still.

@kapso
Copy link
Author

kapso commented Feb 10, 2015

Yea I dont even care about if user_params is required or not, what I want to present to the user is that - first & last name are required ...if that makes sense

@tfausak
Copy link
Collaborator

tfausak commented Feb 10, 2015

If that's the case, why not make first_name and last_name top-level inputs? Something like this maybe:

class CreateUser < ActiveInteraction::Base
  string :first_name, :last_name
  def execute
    # ...
  end
end

If you use it in a controller, you could do this:

class UserController < ApplicationController
  def create
    outcome = CreateUser.run(params[:user])
    # ...
  end
end

@kapso
Copy link
Author

kapso commented Feb 10, 2015

I could :) but the use case I am dealing with - requires to send a user param hash. Basically I am sending in multiple hashes.

@AaronLasseigne
Copy link
Owner

Are you sure they should be going in as multiple hashes and not a merged hash?

@tfausak
Copy link
Collaborator

tfausak commented Feb 10, 2015

If they do have to be multiple hashes, I think this is the best we can do in terms of error handling:

# errors.symbolic
{ user_params: [:missing_nested] }

# errors.messages
{ user_params: ['is missing a nested value (first_name)'] }

# full message
User params is missing a nested value (first_name)

@kapso
Copy link
Author

kapso commented Feb 10, 2015

So our existing business logic is encapsulated inside https://github.com/collectiveidea/interactor (another great project) -- most of our existing interactors accept multiple hashes (user_params, address_params etc) in the interface (and not one merged hash). So lot of existing code is written that way. The fact the user details is nested inside user_params is hidden from the client (in our case API client) -- so nested error message does not make sense. A plain vanilla "First name is required" is more intuitive for the client.

I am looking into the possibility of migrating to active_interaction mainly coz it offers validations which is pretty sweet.

@tfausak
Copy link
Collaborator

tfausak commented Feb 25, 2015

I don't think we can support your use case. It's not possible in general to lift errors from inside a hash to outside it. (See #257 for why.) The error messages we generate should give you all the information you need to handle this in the controller.

class Example < ActiveInteraction::Base
  hash :user_params do
    string :first_name, :last_name
  end
end

outcome = Example.run(user_params: {})
puts outcome.errors.messages[:user_params]
# has an invalid nested value ("first_name" => nil)

@tfausak
Copy link
Collaborator

tfausak commented Mar 13, 2015

I'm going to close this issue. We can't support your use case. If inputs inside hashes have to keep their errors inside the hash. If they didn't, you'd have the potential for collisions. For example, what do you imagine the errors would look like here?

class Example < ActiveInteraction::Base
  hash :a do
    boolean :x
  end
  hash :b do
    string :x
  end

  def execute
    # ...
  end
end

@tfausak tfausak closed this as completed Mar 13, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants