Rails field_with_errors and Bootstrap 4 vertical form - haml

I have a simple rails 5 form for New/Edit using vertical alignment using Bootstrap4. Everything looks fine until I get an error. The .field_with_errors is breaking the alignment.
It seems like the .col-x-x selectors are being ignored once the field_with_errors is introduced. I know bootstrap 4 is still in alpha, but hoping someone has found a work around.
Here is the form:
.container.wow.fadeInUp{style: "visibility: visible; animation-name: fadeInUp;"}
%h2.state New State
.w-75
= errors_for(#state)
.card
= form_for [:admin, #state] do |f|
.card-block
.form-group.row
= f.label :name, class: 'col-sm-4 col-form-label'
.col-sm-5
= f.text_field :name, class: 'form-control'
.form-group.row
.col-sm-3
= f.submit "Save", class: 'btn btn-primary'

you can remove the field_with_error div that breaks your css
Here's a simple trick to do away with those pesky wrappers once and for all. Just add this block to your config/environment.rb file.
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
html_tag.html_safe
end

Difficult to find a good answer to this, as all the old answers seem to refer to .has-error, and this is no longer supported in Bootstrap.
An extention of the answer given by #LifterCoder, inspired by this blog post, allows the label tags to be ignored, but still wrap the other tags with .field_with_error tags.
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
if instance.kind_of?(ActionView::Helpers::Tags::Label)
html_tag.html_safe
else
"<div class=\"field_with_errors\">#{html_tag}</div>".html_safe
end
end

Related

Display only one field from an embedded document with MongoID

I'm a real beginner with MongoDB and MongoID.
I created two scaffolds
class Objet
include Mongoid::Document
field :nom, type: String
embeds_one :coordonnee
end
And
class Coordonnee
include Mongoid::Document
field :adresse1, type: String
field :adresse2, type: String
field :code_postal, type: String
field :ville, type: String
embedded_in :objet
end
That's what I get when creating a new Objet :
Now, I'm trying to show only the field adresse1 for this document, but it doesn't work. I can display only the whole embedded document doing this :
When I do :
<%= #objet.coordonnees.adresse1 %>
I get this error :
undefined method `adresse1' for #<Hash:0x2b2b1f0>
How can I do that ?
EDIT
Doing that, I can display all the elements "Adresse1, adresse2, ville, code_postal" :
Controller
def show
#objet = Objet.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #objet }
end
end
View
<%= #objet.nom %>
<% #objet.coordonnee.each do |t| %>
<%= t[1] %>
<% end %>
But my question is : How to display ONLY one of them ? Such as ville, or code_postal or adresse1... ?
What was your code that works for the full document? It was dropped from your post.
In the mongo Shell, you could do this with dot notation db.collection.find({},{'coordonnees.adresse1':1,'_id':0}) You need to specify the '_id':0 because _id is always returned by default.
The other answer will not work because adresse1 is a subdocument. You must include the reference to coordonnees.
Not hugely familiar with MongoID, but assuming you can make calls straight to mongo, there is a second implicit parameter to all find-like statements called a projection that specifies what exactly you would like to return.
For instance, showing only adresse1 for all items in your collection:
db.collection.find({},{"coordonnees.adresse1": 1, "_id":0})
should return only the adresse1 parameter. I wasn't quite able to tell exactly what context you're displaying the objects in, but regardless of context, api calls to mongo should be fairly straightforward to make. Let me know if I've misinterpreted this question though.
In your posted example, you should change your find function to something like the following:
Objet.find({params[:id]}, {:fields => [coordonnees.adresse1]})
Hope that helps.
I found the solution to my problem.
To display only one element of the hash, I can do :
<%= #objet.coordonnees['adresse1'] %>
I am not sure if you are using embeds_one or embeds_many as you are using singular and plural forms of the relation name interchangeably in your question.
If it is a embeds_one the problem is that you should not iterate on #objet.coordonnee as it is a single document. Your view code should look like:
<%= #objet.nom %>
<%= #objet.coordonnee.address1 %>
If it is a embeds_many, your relation name should be plural, then you should be able to use t.address1 in your view.
# model Objet
embeds_many :coordonnees
# view
<%= #objet.nom %>
<% #objet.coordonnees.each do |t| %>
<%= t.address1 %>
<% end %>

Use translation for submit button

I don't want to use the default
<%= f.submit %>
and have created a helper function for it, which also embeds an icon. The helper function expects a label to put on the newly created button.
I'm calling it like this:
<%= submit_button("icon-plus", I18n.translate("helpers.submit.create")) %>
But now on this text appears on the button:
%{model} toevoegen
Instead of:
Product type toevoegen
If I use the normal submit button then the correct text appears so my yml files are correct. How can I get the correct text to use in the helper?
Helper code:
def submit_button(icon, label)
link_to "javascript:void(0)", :class => 'btn btn-primary', :onclick => "$(this).closest('form').submit()" do
raw('<div class="') + icon + raw(' icon-white"> ') + label +raw('</div>')
end
end
As the I18n guide says, the translate function interpolates variables passed in the %{} brackets using its second argument (a hash).
In your case you need to tell it the model by doing this:
I18n.t("helpers.submit.create", model: "Product type")
If you want a generic option that would work for any model, you can see how Rails itself does it by looking at the source on GitHub - it's something like
I18n.t("helpers.submit.create", model: f.object.class.model_name.human)
As an aside, you don't need to (and probably shouldn't) use raw there. What you are trying to achieve could easily be done with the built-in helpers:
link_to ... do
content_tag :div, label, class: "#{icon} icon-white"
end

Rails simple_form checkboxes for serialized Array field

I am using SimpleForm to build my form.
I have say the following model:
class ScheduledContent < ActiveRecord::Base
belongs_to :parent
attr_accessible :lots, :of, :other, :fields
serialize :schedule, Array
end
I want to construct a form, where among many other fields and associations (this model is actually part of a has_many association already - so quite a complex form) a user is presented with a variable number of days (eg Day 1, Day 2, Day 3, etc) - and each day can be checked or unchecked. So if a user checks Day 1, and Day 5 say - I want to store [1, 5] in the schedule field. Before the form - I can construct a simple array of possible days to choose from, including obviously the days already chosen.
What is the best way to represent this form using SimpleForm's form helpers? If it is not possible to do so - I could use Rails' form helpers too to make it work, but my preference is SimpleForm as the rest of the form is already constructed using SimpleForm.
Yes, you can do it with SimpleForm. Here is an example:
<%= simple_form_for(#user) do |f| %>
<%= f.input :schedule, as: :check_boxes, collection: [['Day 1', 1], ['Day 2', 2]] %>
<%= f.button :submit %>
<% end %>
Answer to an old question, but I had to do something similar recently. To mark already-selected check box options, I used :checked similar to this:
<%=
form.input :schedule, {
as: :check_boxes,
collection: Days.my_scope.map { |day| [day.name, day.id] },
wrapper: :vertical_radio_and_checkboxes,
checked: form.object.schedule
}
%>
Was struggling with this one as well. Finally made it as the haml code below. It makes use of SimpleForm collection_check_boxes method and will output check boxes with labels vertically. List will not show general label in top for the whole checkbox list.
= f.collection_check_boxes :schedule, Day.all, :id, :label_name do |day|
= day.check_box
= day.label
%br

Reload calendar into nested forms (rails 3)

I have a form which contains one model (let's call it Model1) and this models accepts nested attributes from another one (let's call it Model2). I want to be able to save many Model2 records, but I want the view, at the beginning, to show just one set of fields from Model2, and have a button which, if clicked, displays another set of fields from that model, and so on. For this, i'm using the nested_form gem.
All is working well, but the problem is that one of the fields is associated with a datepicker. So, the first Model2 set of fields shows the calendar, but when I click to render the next set of fields, the datepicker, of course, does not get shown anymore (because the Javascript loads only when you get to the page and never again)
The following code shows the button which adds more concepts (Concept is Model2)
<%= f.fields_for :concepts do |concept_form| %>
<%= render "courses/concept_fields", :f=>concept_form%>
<% end %>
<p><%= f.link_to_add t("concepts.add"), :concepts %></p>
And inside courses/concept_fields I have:
<%= f.text_field :collection_date, :value => f.object.collection_date, :class => 'text date_picker tabs' %>
The javascript for the datepicker is included in the layout
Is there any way you can help me? Thanks!
Add and click event handler to the button you use to render the next set of fields to reload the datepicker something like:
$('.render_next_button').click(function(){
// code to reload datepicker
$( "#datepicker" ).datepicker();
});
I've found an answer which solved my problem. It's in this link:
jQuery UI DatePicker with nested_forms Gem
Would look like this:
<script type="text/javascript">
jQuery(function() {
jQuery('form').live('nested:fieldAdded', function(event) {
jQuery(event.field).find('.date_picker').removeClass('hasDatepicker').datepicker();
});
});
</script>

adding size option to file_field tag in rails

ANSWERED
I actually found the answer while formulating the question but I'm posting it any way since some might find this useful(as said here: https://meta.stackexchange.com/questions/49922/should-i-continue-adding-a-question-if-i-have-found-the-answer-myself)
I'm having trouble adding size to a file field in ROR3. Here was my syntax:
= f.file_field :file, :size => "11"
this doesnt appear but creates an file input field with this:
<input type="file" name="soap_test_zip_file[file]" id="soap_test_zip_file_file">
now I KNOW I made it work before so I looked into some old code and found this:
= file_field_tag :file, :size => 11
which outputs this:
<input type="file" size="11" name="file" id="file">
which gives me the correct size, but the wrong file id and name. So I tried this:
<input type="file" size="11" name="soap_test_file_file" id="soap_test_file_file">
which gives me the RIGHT ID, but the WRONG NAME. Question is how do I reproduce that file_field but with the size?
I looked into this answer by Ryan Bigg btw: Problem showing the 'size' attribute for a 'file_field' using Ruby on Rails 3
and he's saying it's a cross browser thing that they render file fields differently. That is the case, but I would like to render a short file field IF the browser can handle it.
I used:
= file_field_tag :soap_test_zip_file, {:name => 'soap_test_zip_file[file]', :size => 11}
This made me override the name(for the controller) and the size
doesn't seem to work for me..
I thought of another alternative :
jquery ..
$('#user_photo_photo').attr('size', 1);
bingo!!
If you want to not rewrite the name attribute you can do something like this :
keep your form
= f.file_field :file, :size => "11"
add an override for the file_field method
# lib/my_override.rb
module ActionView
module Helpers
module FormHelper
def file_field(object_name, method, options = {})
InstanceTag.new(object_name, method, self, options.delete(:object)).to_input_field_tag("file", options.update({:size => options[:size]}))
end
end
end
end
And load it through an initializer
# config/initializers/load_lib.rb
require 'my_override'