Comments (30)
@joneslee85 this is related to #53. We don't handle nested levels of params yet.
from controller.
@jodosha I don't this is related to #53 at all. I think it is not even related to lotus/controller.
On the second look, it turns out that params
which is an instance Lotus::Utils::Attributes
, and this instance does not perform deep symbolise keys upon being initialised.
I question should we symbolising keys at all? There aren't any merits of doing so? Well there are, if you consider 'no-GC' issue (not an issue with Ruby 2.2) and DDoS merits. I am aware that underneath Lotus::Utils::Attributes
is actually Lotus::Utils::Hash
anyway. So I'd like to propose that we drop symbolising hash keys to remove the overhead. Thoughts? /cc @stevehodgkiss
from controller.
I think this behaviour is correct:
params['user'] #=> { "first_name" => "Sean", "last_name" => "Bean" }
params['user'].class #=> Lotus::Utils::Hash
params[:user] #=> { "first_name" => "Sean", "last_name" => "Bean" }
params[:user].class #=> Lotus::Utils::Hash
and this behaviour I think it isn't supported now because the class returned is Utils::Hash and it isn't a Utils::Attributes:
params['user']['first_name'] #=> "Sean"
params[:user][:first_name] #=> "Sean"
I think in Utils::Attributes we should create Utils::Attributes instances for deeped hashes
params['user'] #=> { "first_name" => "Sean", "last_name" => "Bean" }
params['user'].class #=> Lotus::Utils::Attributes
params[:user] #=> { "first_name" => "Sean", "last_name" => "Bean" }
params[:user].class #=> Lotus::Utils::Attributes
from controller.
Related: hanami/validations#43
from controller.
@joneslee85 I think that what @AlfonsoUceda is correct. We need to guarantee that Utils::Attributes
deeply converts nested hashes to instances of Utils::Attributes
. This should guarantee indifferent access at all the levels.
[1] pry(main)> require 'lotus/utils/attributes'
=> true
[2] pry(main)> attrs = Lotus::Utils::Attributes.new(a: 1, b: { c: 3 })
=> #<Lotus::Utils::Attributes:0x007fd7eca8eff0 @attributes={"a"=>1, "b"=>{"c"=>3}}>
[3] pry(main)> attrs.get('a')
=> 1 # CORRECT
[4] pry(main)> attrs.get(:a)
=> 1 # CORRECT
[5] pry(main)> attrs.get('b')
=> {"c"=>3}
[6] pry(main)> attrs.get('b').get('c')
NoMethodError: undefined method `get' for {"c"=>3}:Lotus::Utils::Hash
from /Users/luca/.gem/ruby/2.2.0/gems/lotus-utils-0.3.3/lib/lotus/utils/hash.rb:270:in `method_missing' # INCONSISTENT BEHAVIOR
[7] pry(main)> attrs.get('b')[:c]
=> nil # INDIFFERENT ACCESS ISN'T GUARANTEED
[8] pry(main)> attrs.get('b')['c']
=> 3 # INCONSISTENT ACCESS TO NESTED ATTRIBUTES
RE DDoS and symbols: This is still an issue for Ruby as language. The majority of the VMs that we are trying to target are still affected: MRI 2.2-, JRuby and Rubinius. This is still a concern.
@joneslee85 @stevehodgkiss I think that #53 should take account of another issue too. Right now Params#[]
delegates to @attributes
Β to return the value. We should guarantee that the returning value will respond to #[]
in case of nested params.
- Alternative 1, Alias
Utils::Attributes#get
with#[]
. - Alternative 2, Let
Params#[]
to return another instance ofParams
, when the value is aHash
.
from controller.
@joneslee85 Yet I think it's still related to #53, because we can't deeply symbolize if we aren't able to whitelist nested params. Still related to DDoS attacks via symbols.
from controller.
π alternative 1
from controller.
#71 adds necessary changes to controller for nested params and also fixes this issue
from controller.
This will be fixed with v0.4.0
when we'll only support VMs with 2.2+ mode.
In that case we could use Utils::Hash
and safely symbolize params recursively.
from controller.
@joneslee85 Does Params#get
fixes your problem? With that API, you can safely access nested attributes with the following syntax:
params.get('address.street') # => "Main St."
params.get('some.unknown.params') # => nil
If it helps, please close this ticket. Thank you! π
from controller.
@jodosha doing get
helps. But I guess we should document about it.
from controller.
Has this issue been resolved already? I can still encounter the same issue during Getting Started Guide.
This test will always fail since params[:book][:title]
returns nil
:
it 'creates a new book' do
action.call(params)
action.book.id.wont_be_nil
action.book.title.must_equal params[:book][:title]
end
After changing it to params[:book]['title']
, the test passed. I'm not sure whether this is a bug or by design.
env:
- ruby (2.3.0)
- hanami (0.7.2)
- hanami-utils (0.7.1)
from controller.
@tonytonyjan Thanks for reporting this. That looks like a bug: params
provide "indifferent access" both with strings and symbols. They should be interchangeable.
What happens if you do params.get('book.title')
?
from controller.
NoMethodError: undefined method `get' for #<Hash:0x007ff0d79fbf58>
params
should be a Hanami::Action::Params
instead of Hash
.
What can I do?
source:
# spec/web/controllers/books/create_spec.rb
require 'spec_helper'
require_relative '../../../../apps/web/controllers/books/create'
describe Web::Controllers::Books::Create do
let(:action) { Web::Controllers::Books::Create.new }
let(:params) { Hash[book: { title: 'Confident Ruby', author: 'Avdi Grimm' }] }
before do
BookRepository.clear
end
it 'creates a new book' do
action.call(params)
action.book.id.wont_be_nil
action.book.title.must_equal params[:book]['title']
end
it 'redirects the user to the books listing' do
response = action.call(params)
response[0].must_equal 302
response[1]['Location'].must_equal '/books'
end
end
from controller.
I found that even though it's a Hanami::Action::Params
, params[:book][:title]
returns nil
as well. However, get("book.title")
works.
it 'creates a new book' do
action.call(params)
byebug
action.book.id.wont_be_nil
action.book.title.must_equal params[:book][:title]
end
(byebug) params['hanami.action'].params.class
Web::Controllers::Books::Create::Params
(byebug) params['hanami.action'].params.get('book.title')
"Confident Ruby"
(byebug) params['hanami.action'].params[:book][:title]
nil
(byebug) params['hanami.action'].params[:book]['title']
"Confident Ruby"
from controller.
@tonytonyjan Sorry, I misread your initial comment.
We can't offer "indifferent access" for that unit test. There is this Hash in test:
let(:params) { Hash[book: { title: 'Confident Ruby', author: 'Avdi Grimm' }] }
That we reference directly below:
it 'creates a new book' do
# ...
action.book.title.must_equal params[:book]['title'] # returns nil
end
That is a plain, ol' school, Ruby Hash. If you construct using symbols, it will fail to reach the expected value if you reference the key as string.
~:ruby-2.3.0 β pry
[1] pry(main)> hash = Hash[book: { title: 'Confident Ruby', author: 'Avdi Grimm' }]
=> {:book=>{:title=>"Confident Ruby", :author=>"Avdi Grimm"}}
[2] pry(main)> hash[:book]['title']
=> nil
[3] pry(main)> hash[:book][:title]
=> "Confident Ruby"
[4] pry(main)>
This is exactly the same that is happening in that test.
from controller.
@tonytonyjan Speaking of the actual Params
class, you're right that still fails.
def call(params)
puts params[:book]['title'] # => nil
puts params[:book][:title] # => "Confident Ruby"
end
This is a bug.
from controller.
Is this still open? I'd like to have a try at it with the PR I just submitted.
from controller.
hanami/utils#137 should be able to address this issue, such that:
def call(params)
params['book']['title'] #=> 'Confident Ruby'
params[:book][:title] #=> 'Confident Ruby'
params.get('book.title') #=> 'Confident Ruby'
end
πΉ
from controller.
@Erol @joneslee85 Thanks for taking care of this, but as we planned long time ago, next version of Hanami will support only Ruby 2.2+ with the purpose of avoid indifferent access. All the params will be accessible only with symbols.
from controller.
Using Ruby 2.2.4p230, accessing the title
key via symbol or the get
method in the spec still fails. Accessing the title
key via string succeeds.
params[:book][:title] #=> nil
params[:book]['title'] #=> 'Confident Ruby'
params.get('book.title') #=> NoMethodError: undefined method `get'
from controller.
Are you using hanami-utils:master
?
from controller.
I'd assume the master branch is what's being pulled down as a dependency of the hanami gem in the Gemfile. I'm using rubygems as the source (giving me hanami-utils 0.7.2). However, it looks like rubygems' copy was last updated in May.
Could the issue just be that the hanami-utils on rubygems isn't recent enough?
from controller.
@changecase In order to get hanami-utils
master
, in your Gemfile, add (or update, if it's already there):
gem 'hanami-utils', github: 'hanami/utils'
Then run bundle install
from controller.
Done. Even so, I still get the same set of responses.
params[:book][:title] #=> nil
params[:book]['title'] #=> 'Confident Ruby'
params.get('book.title') #=> NoMethodError: undefined method `get'
hanami-utils
is now at version 0.8.0.
from controller.
That's odd. Could you check if params
is an instance of Hanami::Utils::Attributes
?
from controller.
It is not.
params.is_a? Hanami::Utils::Attributes #=> false
from controller.
Sorry, I meant params[:book]
.
Would you also be able to paste your Gemfile.lock
? I've tried and it works with the following Gemfile
:
source 'https://rubygems.org'
gem 'bundler'
gem 'rake'
gem 'hanami', '0.7.3'
gem 'hanami-model', '~> 0.5'
gem 'hanami-utils', github: 'hanami/utils'
from controller.
@Erol @changecase Hanami::Utils::Attributes
is no longer used and it will be deprecated. It was introduced in the first time because we wanted to provide indifferent access. With the next release we will remove indifferent access, by providing symbol only keys.
@changecase To try it, you should generate a new project using this:
hanami new --hanami-head=true bookshelf
Then edit Gemfile
by adding these gems:
gem 'dry-types', require: false, github: 'dry-rb/dry-types'
gem 'dry-logic', require: false, github: 'dry-rb/dry-logic'
gem 'dry-validation', require: false, github: 'dry-rb/dry-validation'
Please notice that this last step is required because master version of hanami-validations
depends on master of dry-*
gems. This is a temporary workaround. With hanami-0.8.0
you don't need to worry about fiddling with Gemfile
anymore.
from controller.
Thanks @jodosha
from controller.
Related Issues (20)
- Flash #empty? returns true when it's not (after a re-direct) HOT 2
- Hanami::Action::Flash to use swappable JSON backend HOT 2
- Flash message appears twice (redux) HOT 3
- Exception Handling in Production HOT 19
- RuntimeError: can't add a new key into hash during iteration HOT 8
- Compatability issue with hanami-controller 2.0.0.alpha1 HOT 2
- Is `#request` supposed to be memoized for actions? HOT 2
- Standalone actions prevent using non-keyword parameters in `#initialize` (v2) HOT 3
- [2.0.0.alpha1] Uninitialized constant Hanami::Controller::Configuration (NameError) HOT 2
- Handling `config` and other class-level macros HOT 3
- accept syntax in README no longer seems supported HOT 1
- Action params are not coerced? HOT 5
- Badly encoded cookie strings from Safari results in an error HOT 3
- HTTP status 418 is missing HOT 1
- Issue with multipart/form-data format HOT 1
- Support CSRF by HTTP header HOT 4
- Support for hanami-validations/dry-validations `rule(...)`
- Documentation about Controller/Router integration is incorrect HOT 7
- Fix Response#send_file implementation
- handle_exception should allow exception names as strings
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from controller.