README.md in decanter-0.7.1 vs README.md in decanter-0.7.2

- old
+ new

@@ -53,11 +53,11 @@ end end def update @trip = Trip.find(params[:id]) - + if @trip.decant_update(params[:trip]) redirect_to trips_path else render "new" end @@ -137,21 +137,21 @@ ``` You'll also notice that instead of ```@trip = Trip.new(params[:trip])``` we do ```@trip = Trip.decant_new(params[:trip])```. ```decant_new``` is where the magic happens. It is converting the params from this: ```ruby -{ +{ name: "My Trip", start_date: "01/15/2015", end_date: "01/20/2015" } ``` to this: ```ruby -{ +{ name: "My Trip", start_date: Mon, 15 Jan 2015, end_date: Mon, 20 Jan 2015 } ``` @@ -161,16 +161,18 @@ Adding Custom Parsers --- In the above example, start_date and end_date are ran through a DateParser that lives in Decanter. Let's take a look at the DateParser: +** Note this changed in version 0.7.2. Now parser must inherit from Decanter::Parser::ValueParser or Decanter::Parser::HashParser instead of Decanter::Parser::Base ** + ```ruby -class DateParser < Decanter::ValueParser::Base +class DateParser < Decanter::Parser::ValueParser allow Date - parser do |name, value, options| + parser do |value, options| parse_format = options.fetch(:parse_format, '%m/%d/%Y') ::Date.strptime(value, parse_format) end end ``` @@ -180,11 +182,11 @@ You'll notice that the above ```parser do``` block takes a ```:parse_format``` option. This allows you to specify the format your date string will come in. For example, if you expect "2016-01-15" instead of "01/15/2016", you can adjust the TripDecanter like so: ```ruby # app/decanters/trip_decanter.rb -class TripDecanter < Decanter::Base +class TripDecanter < Decanter::ValueParser input :name, :string input :start_date, :date, parse_format: '%Y-%m-%d' input :end_date, :date, parse_format: '%Y-%m-%d' end ``` @@ -196,17 +198,45 @@ ``` **lib/decanter/parsers/date_parser** ```ruby -class DateParser < Decanter::ValueParser::Base - parser do |name, value, options| +class DateParser < Decanter::Parser::ValueParser + parser do |value, options| # your parsing logic here end end ``` + +By inheriting from Decanter::Parser::ValueParser, the assumption is that the value returned from the parser will be the value associated with the provided key. If you need more control over the result, for example, you want a parser that returns multiple key value pairs, you should instead inherit from Decanter::Parser::HashParser. This requires that the value returned is a hash. For example: + +```ruby +class KeyValueSplitterParser < Decanter::Parser::HashParser + ITEM_DELIM = ',' + PAIR_DELIM = ':' + + parser do |name, val, options| + # val = 'color:blue,price:45.31' + + item_delimiter = options.fetch(:item_delimiter, ITEM_DELIM) + pair_delimiter = options.fetch(:pair_delimiter, PAIR_DELIM) + + pairs = val.split(item_delimiter) # ['color:blue', 'price:45.31'] + + hash = {} + pairs.each do |pair| + key, value = pair.split(pair_delimiter) # 'color', 'blue' + hash[key] = value + end + return hash + end +end +``` + +The ```parser``` block takes the 'name' as an additional argument and must return a hash. + Nested Example --- Let's say we have two models in our app: a Trip and a Destination. A trip has many destinations, and is prepared to accept nested attributes from the form. @@ -271,11 +301,11 @@ Each of the destinations in our params[:trip] are automatically parsed according to the DestinationDecanter inputs set above. This means that ```arrival_date``` and ```departure_date``` are converted to Ruby Date objects for each of the destinations passed through the nested params. Yeehaw! Non Database-Backed Objects --- -Decanter will work for your non database-backed objects as well. We just need to call ```decant``` to parse our params according to our decanter logic. +Decanter will work for your non database-backed objects as well. We just need to call ```decant``` to parse our params according to our decanter logic. Let's say we have a search filtering object called ```SearchFilter```. We start by generating our decanter: ``` rails g decanter SearchFilter start_date:date end_date:date city:string state:string @@ -303,13 +333,16 @@ --- Decanter comes with the following parsers: - boolean - date -- datetime +- date_time - float - integer +- join +- key_value_splitter +- pass - phone - string As an example as to how these parsers differ, let's consider ```float```. The float parser will perform a regex to find only characters that are digits or decimals. By doing that, your users can enter in commas and currency symbols without your backend throwing a hissy fit. @@ -320,37 +353,37 @@ ``` Squashing Inputs --- -Sometimes, you may want to take several inputs and combine them into one finished input prior to sending to your model. For example, if day, month, and year come in as separate parameters, but your database really only cares about start_date. +Sometimes, you may want to take several inputs and combine them into one finished input prior to sending to your model. For example, if day, month, and year come in as separate parameters, but your database really only cares about start_date. ```ruby class TripDecanter < Decanter::Base - input [:day, :month, :year], :squash_date, key: :start_date + input [:day, :month, :year], :squash_date, key: :start_date end ``` ``` rails g parser SquashDate ``` ```ruby # lib/decanter/parsers/squash_date_parser.rb -class SquashDateParser < Decanter::Parser::Base - parser do |name, values, options| +class SquashDateParser < Decanter::Parser::ValueParser + parser do |values, options| day, month, year = values.map(&:to_i) Date.new(year, month, day) end end ``` No Need for Strong Params --- -Since you are already defining your expected inputs in Decanter, you really don't need strong_params anymore. +Since you are already defining your expected inputs in Decanter, you really don't need strong params anymore. In order to tell Decanter to ignore the params not defined in your Decanter, just add the ```strict``` flag to your Decanters: ```ruby class TripDecanter < Decanter::Base @@ -367,5 +400,27 @@ strict :with_exception input :name end ``` + +Configuration +--- + +You can generate a local copy of the default configuration with ```rails generate decanter:install```. This will create the initializer ```../config/initializers/decanter.rb```. + +Starting with version 0.7.2, the default strict mode is ```:with_exception```. If this is what you prefer, you no longer have to set it in every decanter. You can still set this on individual decanters or you can configure it globally in the initializer: + +```ruby +# ../config/initializers/decanter.rb + +Decanter.config do |config| + config.strict = true +end + +# Or + +Decanter.configuration.strict = true +``` + +Likewise, you can put the above code in a specific environment configuration. +