I'm in the middle of the process of upgrading a Rails 3.2 app to Rails 4.
I'm working on replacing the attr_accessible from the models with Strong Params in controller.
I noticed that the #permit method behaves a bit different on the 3.2 I'm upgrading than it should behave in a Rails 4 app. In order to validate my suspicion I created a new Rails 4 app from scratch and tested the same code while getting a different outcome:
Rails 3.2 app that is currently being upgraded
[9] pry(main)> x = { attr1: { attr2: "val1", attr3: "val2"}, attr4: "val3", attr5: "val4", attr6: { attr7: "val5"}}
=> {:attr1=>{:attr2=>"val1", :attr3=>"val2"}, :attr4=>"val3", :attr5=>"val4", :attr6=>{:attr7=>"val5"}}
[10] pry(main)> params = ActionController::Parameters.new x
=> {"attr1"=>{"attr2"=>"val1", "attr3"=>"val2"}, "attr4"=>"val3", "attr5"=>"val4", "attr6"=>{"attr7"=>"val5"}}
[11] pry(main)> params.require(:attr1)
=> {"attr2"=>"val1", "attr3"=>"val2"}
[12] pry(main)> params.permit(:attr1)
ActionController::UnpermittedParameters: found unpermitted parameters: attr1, attr4, attr5, attr6
[19] pry(main)> params.permit(:attr4)
ActionController::UnpermittedParameters: found unpermitted parameters: attr1, attr5, attr6
Rails 4 app
2.2.3 :009 > x = { attr1: { attr2: "val1", attr3: "val2"}, attr4: "val3", attr5: "val4", attr6: { attr7: "val5"}}
=> {:attr1=>{:attr2=>"val1", :attr3=>"val2"}, :attr4=>"val3", :attr5=>"val4", :attr6=>{:attr7=>"val5"}}
2.2.3 :012 > params = ActionController::Parameters.new x
=> {"attr1"=>{"attr2"=>"val1", "attr3"=>"val2"}, "attr4"=>"val3", "attr5"=>"val4", "attr6"=>{"attr7"=>"val5"}}
2.2.3 :013 > params.require(:attr1)
=> {"attr2"=>"val1", "attr3"=>"val2"}
2.2.3 :014 > params.permit(:attr1)
=> {}
2.2.3 :032 > params.permit(:attr4)
=> {"attr4"=>"val3"}
I use the protected_attributes gem during the upgrade and I also placed this code in config/initializers/strong_parameters.rb:
ActiveRecord::Base.send(:include, ActiveModel::ForbiddenAttributesProtection)
# config.action_controller.always_permitted_parameters = %w( controller action format )
module ActionController
class Parameters
remove_const(:NEVER_UNPERMITTED_PARAMS) if (defined?(NEVER_UNPERMITTED_PARAMS))
NEVER_UNPERMITTED_PARAMS = %w( controller action format)
end
end
Do you have any idea what the problem might be?
You'll need to permit all nested parameters, see here: http://api.rubyonrails.org/classes/ActionController/Parameters.html#method-i-permit.
So in your case, for the first attribute you should do
params.permit(attr1: [:attr2, :attr2])
and likewise for the other parts of your hash.
Apparently the reason I was getting this error was because I had this setting in my config/application.rb
config.action_controller.action_on_unpermitted_parameters = :raise
Deleting it gave me the ability to permit only the params I wanted.
Related
I am working on upgrading rails application, I have a method unserialize_attribue in rails 3 but I am not able to see this method in rails 5.
What is the alternative for unserialize_attribute in rails 5 or any suggestion on what can I do, Thanks
unserialize_attribute is removed from rails-5 but you can unserialized value in different way,
Method:1
> #user.accessible_attribute
# => {"attr1"=>["Email id"], "attr2"=>["First Name"], "attr3"=>["Last Name"]}
> #user.attributes_before_type_cast['accessible_attribute']
# => "--- !ruby/hash:ActionController::Parameters\nattr1:\n- Email id\nattr2:\n- First Name\nattr3:\n- Last Name\n"
Method:2
#user.instance_variable_get(:#attributes)['accessible_attribute'].value_before_type_cast
# => "--- !ruby/hash:ActionController::Parameters\nattr1:\n- Email id\nattr2:\n- First Name\nattr3:\n- Last Name\n"
Method:3
> #accessible_attribute = ActiveRecord::Base.connection.execute("SELECT accessible_attribute FROM users WHERE id = #{#user.id}")
(0.4ms) SELECT accessible_attribute FROM users WHERE id = 3
# => #<Mysql2::Result:0xe0fc374 #query_options={:as=>:array, :async=>false, :cast_booleans=>false, :symbolize_keys=>false, :database_timezone=>:utc, :application_timezone=>nil, :cache_rows=>true, :connect_flags=>-2147442171, :cast=>true, :default_file=>nil, :default_group=>nil, :adapter=>"mysql2", :encoding=>"utf8mb4", :collation=>"utf8mb4_unicode_ci", :database=>"example_development", :pool=>5, :username=>"root", :password=>"password", :socket=>"/var/run/mysqld/mysqld.sock", :flags=>2}>
> #accessible_attribute.first[0]
# => "--- !ruby/hash:ActionController::Parameters\nattr1:\n- Email id\nattr2:\n- First Name\nattr3:\n- Last Name\n"
Note: Precisely, Some prefer to take attribute value unserialized by #user.accessible_attribute.to_yaml also.
I got it working using serializable_hash and it is available in rails 3 as well as in rails 5
I have this code written in rails 3
unserialized_value = unserialize_attribute(options[:serialized_column]) || { }
which I changed to
unserialized_value = self.serializable_hash[options[:serialized_column]] || { }
both method returns the same hash object.
I am migrating code from Rails 3 to Rails 5.1.6 and Ruby 2.5. I am facing strange issue. I have written after_initialize callback in model and assigning default value to field. The field is serialize and when there is nil in that field it will assign default value inside the callback.
Here is my code for clear picture
class MyModel < ActiveRecord::Base
serialize :settings
after_initialize :set_default_setting
def set_default_setting
self.settings = self.settings || {my_fields: ["a", "b", "c"]}
end
end
Here is my Rails console log :
[1] 2.5.0 :135 > md = MyModel.find(1)
=> #<MyModel:0x00007fe433608348
id: 1,
settings: <ActionController::Parameters permitted: >,
created_at: Tue, 16 Jan 2018 08:45:26 GMT +00:00,
updated_at: Fri, 04 May 2018 10:50:20 BST +01:00>
[2] 2.5.0 :136 > md.settings
=> <ActionController::Parameters permitted: >
[3] 2.5.0 :137 > md.settings.nil?
=> false
My question is why <ActionController::Parameters permitted: > is being added in to nil field ? when I execute nil? method it should return me nil. Above code was working fine with Rails 3.2 and Ruby 2.0 from which I am upgrading to Rails 5 and Ruby 2.5
Any help will be appreciated.
Thank you in Advance.
What is the difference between Ruby’s Hash and ActiveSupport’s HashWithIndifferentAccess? Which is the best for dynamic hashes?
Below is the simple example that will show you difference between simple ruby hash & a "ActiveSupport::HashWithIndifferentAccess"
HashWithIndifferentAccess allows us to access hash key as a symbol or string
Simple Ruby Hash
$ irb
2.2.1 :001 > hash = {a: 1, b:2}
=> {:a=>1, :b=>2}
2.2.1 :002 > hash[:a]
=> 1
2.2.1 :003 > hash["a"]
=> nil
ActiveSupport::HashWithIndifferentAccess
2.2.1 :006 > hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1, b:2)
NameError: uninitialized constant ActiveSupport
from (irb):6
from /home/synerzip/.rvm/rubies/ruby-2.2.1/bin/irb:11:in `<main>'
2.2.1 :007 > require 'active_support/core_ext/hash/indifferent_access'
=> true
2.2.1 :008 > hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1, b:2)
=> {"a"=>1, "b"=>2}
2.2.1 :009 > hash[:a]
=> 1
2.2.1 :010 > hash["a"]
=> 1
class HashWithIndifferentAccess is inherited from ruby "Hash" & above special behavior is added in it.
In Ruby Hash:
hash[:key]
hash["key"]
are different. In HashWithIndifferentAccess as the name suggests, you can access key either way.
Quoting official documentation to this:
Implements a hash where keys :foo and "foo" are considered to be the
same.
and
Internally symbols are mapped to strings when used as keys in the
entire writing interface (calling []=, merge, etc). This mapping
belongs to the public interface. For example, given:
hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
You are
guaranteed that the key is returned as a string:
hash.keys # => ["a"]
I'm building a json object in rails as follows:
#list = Array.new
#list << {
:created_at => item.created_at
}
end
#list.to_json
Problem is this gets received by the browser like so:
"created_at\":\"2000-01-01T01:31:35Z\"
Which is clearly not right, in the DB it has:
2011-06-17 01:31:35.057551
Why is this happening? Any way to make sure this gets to the browser correctly?
Thanks
You need to do some testing / debugging to see how that date is coming through.
For me, in Rails console (Rails 3.0.9, Ruby 1.9.2)
ruby-1.9.2-p180 :014 > d = Date.parse("2011-06-17 01:31:35.057551")
=> Fri, 17 Jun 2011
ruby-1.9.2-p180 :015 > #list = {:created_at => d}
=> {:created_at=>Fri, 17 Jun 2011}
ruby-1.9.2-p180 :016 > #list.to_json
=> "{\"created_at\":\"2011-06-17\"}"
i.e. it's just fine. Can you see whether the date is really ok?
The trouble lies with the way to_json escapes characters. There is a very good post on the subject here:
Rails to_json or as_json
You may need to look into overriding as_json.
I wish to make my code a little more readable by calling #rando on any array and retrieve a random element (rando because a rand() method already exists and I don't want there to be any confusion).
So I opened up the class and wrote a method:
class Array
def rando
self[ rand(length) ]
end
end
This seems far too straightforward.
When I open up irb, and type arr = %w(hi bye) and then arr.rando I get either hi or bye back. That's expected. However, in my rails console, when I do the same thing, I get ArgumentError: wrong number of arguments (1 for 0)
I've been tracing Array up the rails chain and can't figure it out. Any idea?
FWIW, I'm using rails 2.3.11 and ruby 1.8.7
Works fine in my case :
Loading development environment (Rails 3.0.3)
ruby-1.9.2-p180 :001 > class Array
ruby-1.9.2-p180 :002?> def rando
ruby-1.9.2-p180 :003?> self[ rand(length) ]
ruby-1.9.2-p180 :004?> end
ruby-1.9.2-p180 :005?> end
=> nil
ruby-1.9.2-p180 :006 > arr = %w(hi bye)
=> ["hi", "bye"]
ruby-1.9.2-p180 :007 > arr.rando
=> "bye"