Changes in the form are not saved to database - ruby-on-rails-3

I'm trying to add a date field to my form.
I added bootstrap-datepicker-rails gem, all required css and javascript.
When I choose the date in the calendar and click Save, it's not updated in the database.
Here's the code of the form:
= simple_form_for #model
= f.input :date_last, :required => true,
:input_html => { data: {behaviour: "datepicker"}},
:as => :string
= f.button :submit, 'Save', :class => 'btn btn-primary'
I think this might have to do with formats, but not sure where to look at.
Update
It works when I change default format to yyyy-mm-dd (default is mm/dd/yyyy):
$('[data-behaviour~=datepicker]').datepicker({"format": "yyyy-mm-dd", "weekStart": 1, "autoclose": true});

I just answered a similar question here and have included my answer below:
I also needed to get this working and support multiple locales that do not use US centric date formats, eg: en-AU (Australia) which has the date format dd/mm/yyyy.
The Problem
Rails expects the date format to be yyyy-mm-dd from the browser, yet you want to display the date in the user's locale. Whilst the date control allows you to specify the format for display it does NOT allow you to separately specify the format to be sent back to the server.
The Solution
Build a hidden input field that sends the correct format back to your rails server. I do this with with a custom simple_form input control that builds both the date-picker input field and a hidden field, and use some javascript to convert to the rails date when the input control changes.
The upshot is you can have a nice bootstrap date-picker in rails and use it with simple_form as follows:
<%= f.input :date, as: :bootstrap_datepicker %>
Or to use a long date format:
<%= f.input :date, as: :bootstrap_datepicker, input_html: { format: :long } %>
Implementation
Create or edit the following files:
Gemfile
gem 'bootstrap-sass'
gem 'bootstrap-datepicker-rails'
config/locales/en-AU.yml
en-AU:
date:
datepicker:
default: "dd/mm/yyyy"
long: "dd MM, yyyy"
formats:
default: ! '%d/%m/%Y'
long: ! '%d %B, %Y'
config/locales/en-US.yml
en-US:
date:
datepicker:
default: "mm/dd/yyyy"
long: "MM dd, yyyy"
formats:
default: "%m/%d/%Y"
long: ! '%B %d, %Y'
app/assets/stylesheets/application.css.scss
#import "bootstrap-responsive";
#import "bootstrap-datepicker";
app/assets/javascripts/application.js.coffee
#= require bootstrap
#= require bootstrap-datepicker
#= require bootstrap-datepicker-rails
Alternatively, app/assets/javascripts/application.js
//= require bootstrap
//= require bootstrap-datepicker
//= require bootstrap-datepicker-rails
app/assets/javascripts/bootstrap-datepicker-rails.js.coffee
$ ->
# convert bootstrap-datepicker value to rails date format (yyyy-mm-dd) on our hidden field
$(document).on 'changeDate', '.bootstrap-datepicker', (evt) ->
rails_date = evt.date.getFullYear() + '-' + ('0' + (evt.date.getMonth() + 1)).slice(-2) + '-' + ('0' + evt.date.getDate()).slice(-2)
$(this).next("input[type=hidden]").val(rails_date)
app/inputs/bootstrap_datepicker_input.rb
class BootstrapDatepickerInput < SimpleForm::Inputs::Base
def input
text_field_options = input_html_options.with_indifferent_access
format = text_field_options.delete(:format)
hidden_field_options = text_field_options.dup
hidden_field_options[:class] = text_field_options[:class].dup # so they won't work with same array object
hidden_field_options[:id] = "#{attribute_name}_hidden"
text_field_options[:class] << 'bootstrap-datepicker'
text_field_options[:type] = 'text'
text_field_options[:value] ||= format_date(value(object), format)
set_data_option text_field_options, 'date-format', I18n.t(format, scope: [:date, :datepicker], default: :default)
default_data_option text_field_options, 'provide', 'datepicker'
return_string =
"#{#builder.text_field(attribute_name, text_field_options.to_hash)}\n" +
"#{#builder.hidden_field(attribute_name, hidden_field_options.to_hash)}\n"
return return_string.html_safe
end
protected
def default_data_option(hash, key, value)
set_data_option(hash,key,value) unless data_option(hash, key)
end
def data_option(hash, key)
hash[:data].try(:[],key) || hash["data-#{key}"]
end
def set_data_option(hash, key, value)
hash[:data].try(:[]=,key,value) || (hash["data-#{key}"] = value)
end
def value(object)
object.send #attribute_name if object
end
def format_date(value, format=nil)
value.try(:strftime, I18n.t(format, scope: [ :date, :formats ], default: :default))
end
end

I encountered similar problem and converting format in create action solved it for me:
def create
.....
#person.dob = DateTime.strptime(params[:person][:dob], '%m/%d/%Y').to_date
.....
#person.save
.....
end

Andrew Hacking's answer worked great for me, with two small changes to app/inputs/bootstrap_datepicker_input.rb. I'm using Rails 4.2.0. It was ignoring the value in the hidden field as a duplicate (since the text input and hidden input have identical "name" attributes). I switched:
"#{#builder.text_field(attribute_name, text_field_options.to_hash)}\n"
... to this:
"#{#builder.text_field(attribute_name.to_s+'_box',text_field_options.to_hash)}\n" +
Also, I was losing wrapper options, so I added an argument to input and merged the wrapper options into the html options.
This:
def input
text_field_options = input_html_options.with_indifferent_access
...
... became:
def input(wrapper_options)
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
text_field_options = merged_input_options.with_indifferent_access
...

I´ve used the anwser from Andrew. It worked well for me, except that it not displayed the localized month names correct (For example July instead of Juli).
Here is my approach, if you want to use a localized version for your date_picker.
By default the bootsrap-datepicker gem loads all language versions.
If you want for example to load only the english and german version you have to change application.js
from
//= require bootstrap-datepicker
to
//= require bootstrap-datepicker/core
//= require bootstrap-datepicker/locales/bootstrap-datepicker.en-GB.js
//= require bootstrap-datepicker/locales/bootstrap-datepicker.de.js
Nest step is to change BootstrapDatepickerInput
What we want now is that the language is dynamically choosen from a given parameter.
so add the following line to you Input class inside of the input method
set_data_option text_field_options, 'date-language', input_html_options[:locale]
In our view we can call now the form with
= f.input :your_attribute_name, as: :bootstrap_datepicker, input_html: { locale: locale }

Related

Rails. Validations for many locales at the same time

I have a bilingual web site with two locales: en and ru.
I want my site to have i18n. I use 'globalize3' and 'easy_globalize3_accessors' gems.
There are departments I can create and edit with standard forms.
Locales are given from URL: example.com/en/departments/ or example.com/ru/departments/
Now if I want to create a new department item, I would see such a thing:
A main form for current locale (I18n.locale).
A checkbox to add a translation on the same page.
If checkbox is active, show another form for another locale right next to the main form.
The most important thing — validations for each locale must be different. Say, for en it should pass ASCII symbols; for ru — Cyrillic ones.
My problem is number 4. I can't get my validations work with a checkbox.
The main problem is: checkbox active? If yes, show another form and run validations for it. If no, show nothing and don't run validations for that form, pass it empty.
For now, if I fill in two forms, everything works like a charm.
Ok. What I tried.
Model
class Department < ActiveRecord::Base
attr_accessible :name, :translations_attributes
translates :name, fallbacks_for_empty_translations: true
accepts_nested_attributes_for :translations
# The inline class Translation is a hack to solve
# "Can't mass-assign protected attributes: locale"
# See https://github.com/svenfuchs/globalize3/issues/128#issuecomment-11480650
class Translation
attr_accessible :locale, :name
validates :name, uniqueness: true
validates :name, format: {with: /\A[-а-яА-Я -]+\Z/}, if: ->(l) {l.locale.to_s == 'ru'}
validates :name, format: {with: /\A[-a-zA-Z -']+\Z/}, if: ->(l) {l.locale.to_s == 'en'}
end
end
Controller
def new
#department = Department.new
end
def create
#department = Department.new(params[:department])
#department.save ? (redirect_to action: :index) : (render :new)
end
View (new.haml.html) without checkbox
= form_for #department, url: {action: :create} do |f|
%h2
- f.globalize_fields_for_locale I18n.locale do |g|
= "Translation for"
= I18n.locale
= g.label t("department.form.new.label.name")
= g.text_field :name
%hr
%h2
- I18n.available_locales.each do |locale|
- next if locale == I18n.locale
%br
- f.globalize_fields_for_locale locale do |g|
= "Translation for"
= locale
= g.label t("department.form.new.label.name")
= g.text_field :name
= f.submit t("department.create.link"), class: "btn"
Help me understand what I have to do, please.

including rails object in meta tags keywords

I'd like to include a rails object in my keywords as well as straight text but the code is clearly not the right way to do it...how can I do this?
set_meta_tags :keywords => %w[keyword1 keyword2 #{params[:hospital]}]
You might want to have a look at two plug-ins for including rails object in meta tags:
Meta Magic: https://github.com/lassebunk/metamagic
Head Liner: https://github.com/mokolabs/headliner
Edit: For Meta tag gem
What I usually do is write a meta helper that I simply stick in my ApplicationHelper, that looks like this:
def meta(field = nil, list = [])
field = field.to_s
#meta ||= {
'robots' => ['all'],
'copyright' => ['My Copyright'],
'content-language' => ['en'],
'title' => [],
'keywords' => []
}
if field.present?
#meta[field] ||= []
case list.class
when Array then
#meta[field] += list
when String then
#meta[field] += [list]
else
#meta[field] += [list]
end
case field
when 'description' then
content = truncate(strip_tags(h(#meta[field].join(', '))), :length => 255)
else
content = #meta[field].join(', ')
end
return raw(%(<meta #{att}="#{h(field)}" content="#{h(content)}"/>))
else
tags = ''
#meta.each do |field, list|
tags += meta(field)+"\n"
end
return tags.rstrip
end
end
You can simply set meta tags in your views, by adding a call to meta() in it. So in an articles/show.html.erb you might add this to the top of your view:
<% meta(:title, #article.title) %>
And in your layouts, you add it without any parameters, so it'll spit out the meta tags.
<%= meta %>
Or have it output an individual tag:
<%= meta(:title) %>
I bet you there's more elegant solutions, though.
But if you were looking for something already implemented in Rails you're out of luck.
Thanks.
Try this in your view as it worked for me (using meta-tags gem):
<% keywords [[#modelname.keyword1], [#modelname.keyword2]] %>
and you cad additional keywords in text format by adding them within the ruby in the following format ['keyword3']

Setting default value for a timebox

I am using the Datebox(timebox mode) jquerymobile plugin in my Rails app to choose some hours. I am trying to set the default value by using defaultPickerValue, but I dont how to add it.
I can only find this document about it
http://dev.jtsage.com/jQM-DateBox1/demos/api/matrix.html#&ui-page=1-2
I have tried a lot variations like this:
<%= builder.text_field :start_time, "data-role" => "datebox", "data-options" => '{"mode": "timebox", "minuteStep": 15, "defaultPickerValue": "[12,0]" }' %>
and
<%= builder.text_field :end_time, "data-role" => "datebox", "defaultPickerValue" => "[12,0]", "data-options" => '{"mode": "timebox", "minuteStep":15 }'%>
Is it only possible to set by script on on load?
You can do it whenever you want.
Take a look at this example:
var defaultPickerValue = [12, 0, 0]; // 12 hour, 0 minutes, 0 seconds
$('#datePickerID').data('timebox').options.defaultPickerValue = defaultPickerValue;
Use this format to set any other needed option.
Or better do it like this. It is an easier solution.

Rails 3/3.1 and I18n: Validation hits when switching between languages

The database is seeded with values in english language and format, e.g., :hourlyrate => 20.90. On first start (language is english by default), the input form displays the content of the field correctly. I can modify and save, no problem.
If I switch to german, the number is displayed correctly as 20,90. If I edit anything on this form, I can not save again, as the validation catches the number as not being valid.
My question is, do I have to perform corrections in my controller before saving, or did I miss some built-in function of Rails?
Relevant parts of the code
Helper:
def my_number_with_precision(value)
if value
# value
number_with_precision(value, :precision => 2)
end
end
Validation:
validates :hourlyrate, :numericality => { :greater_or_equal_than => 0, :message => " is an invalid number or below zero" }
Form:
<div class="input">
<%= f.text_field :hourlyrate, :value => my_number_with_precision(f.object.hourlyrate) %>
</div>
Gemfile
gem 'rails-i18n'
I came up with one of the following solutions - language specific code:
def parse_i18n(value)
if I18n.locale = 'de'
value.gsub(',', '.')
else
value
end
end
def parse_i18n(value)
value.gsub(I18n.t("number.currency.format.unit"),'').
gsub(I18n.t("number.currency.format.delimiter"), '').
gsub(I18n.t("number.currency.format.separator"), '.')
end

datepicker jquery ui and rails 3(.1)

Hi i am using the date picker jquery ui in combination with rails 3.1. The date picker looks brilliant, only the date isn't stored in the database? Only sometimes...? So that's a difficult error.
This is my .js file:
$(function() {
$("#question_deadline").datepicker({ duration: 'fast', maxDate: '+2m', minDate: 'now', showOn: "button", buttonImage: "calendar.gif", buttonImageOnly: true });
$("#question_deadline").datepicker("option", "showAnim", "drop");
$("#question_deadline").datepicker("option", "dateFormat", "DD, d MM, yy");
});
In my controller there's just plain rails script:
def create
#question = Question.new(params[:question])
if #question.save
redirect_to questions_path, :notice => "Successfully created question."
else
setup_questions
render :index
end
end
In views file _form.html.erb i use a text_field to display the date:
<div class="field">
<%= f.label :content, "Question" %><br />
<%= f.text_field :content, :placeholder => "type your question here.." %>
<%= f.text_field :deadline %><br />
</div>
Are there people who have experience with datepiacker jquery ui and rails, the ryan bates episode, didn't solve it, i think that was written in rails 2.3?
Regards,
Thijs
First, you need to show us the view where you have the datepicker element. If it's like this:
<input type="text" name="question_deadline" id="question_deadline" />
When you submit this form, the parameters you receive in your controller (in the method "create") is called question_deadline. So in that create method you should first write:
if params[:question_deadline] != ""
params[:question][:question_deadline] = params[:question_deadline]
end
#add a else if this date field is compulsory in the database
This step is important because the create method will read stuff from params[:question][:question_deadline] not from params[:question_deadline] which is returned from the view.
Thus params[:question][:question_deadline] is empty when you do #question.save
To display the date, you also need to show us the controller "show" method that should be something like:
#question = Question.find(params[:id]) #or any sql request that returns info about a question.
Then in the view you can retrieve it simply with:
<%= #question.question_deadline%>
Maybe with more code from you controller and view I can elaborate on that.
I think, Rails/Ruby is not able to parse a date in this format:
$("#question_deadline").datepicker("option", "dateFormat", "DD, d MM, yy");
// full day name, day (w/o leading zero), full month name, 4-digit year
In your controller, you might want to add a line such as
def create/update
...
#question.deadline = DateTime.strptime(params[:question][:deadline], '%A, %d %B, %Y')
# assuming my jquery-to-ruby format-mapping is adequate ;-)
if #question.save
...
end
Beware, that this code easily breaks on malformed date strings.
If you don't want to change the format to, e.g. 'yy-mm-dd' (in Ruby-land it's '%Y-%m-%d'), you may want to populate the selected date to another HTML element using the altField option and hide the actual datepicker input field via CSS:
$("#somewhere_else").datepicker(
dateFormat: "%yy-%mm-%dd",
altField: "#question_deadline",
altFormat: "DD, d MM, yy",
...
);
<%= form_for #question do |f| %>
...
<%= text_field_tag 'somewhere_else', #question.deadline %>
<%= f.hidden_field :deadline %>
...
<% end %>
That'll work, at least for me :-)
—Dominik
The other option is to update the way ActiveSupport parses dates. This is outlined in Default Date Format in Rails (Need it to be ddmmyyyy)