Rails Bootstrap how to format form_for (width grid collapses)
take a look at bootstrap v3 doc here http://getbootstrap.com/css/#forms-horizontal
and you don't need to add form tag
since you are already using form_for
<%= form_for @user, :html => {:class => "form-horizontal center"} do |f| %>
<div class="form-group">
<%= f.label :fname, "First name:", class: "col-md-4 control-label" %>
<div class="col-md-8">
<%= f.text_field :fname, class: "form-control" %>
</div>
</div>
<div class="form-group">
<%= f.label :lname, "Last name:", class: "col-md-4 control-label" %>
<div class="col-md-8">
<%= f.text_field :lname, class: "form-control" %>
</div>
</div>
<div class="form-group">
<%= f.label :comments, "Comments:", class: "col-md-4 control-label" %>
<div class="col-md-8">
<%= f.text_field :comments, class: "form-control" %>
</div>
</div>
<div class="radio">
<%= f.radio_button :attend, 'yes', :checked => true %> I will attend.
<br />
<%= f.radio_button :attend, 'no', :checked => false %> I will not attend.
</div>
<div class="checkbox">
<%= f.check_box :workshop %> Checkbox Description
</div>
<%= f.submit "Submit", class: "btn btn-default btn-primary" %>
<% end %>
Form doesn't align properly on Safari but works well on Chrome
After reading through grid columns
in bootstrap, I figured there is not reason my code should not work well on the two browsers. The problem being that Safari calculates differently.
So, I figured out grid column
already past 12 column in Bootstrap 3 and 24 in Bootstrap 4. Upon adjusting the column I feel should be smaller and extend/increased the number of the part that wrap to new line. it works fine.
In other words, I increase this part .col-xs-6
in the snippet below to .col-xs-8
, while I reduced others:
.col.col-xs-8
= f.datagrid_label :created_at
.form-inline # This is what I used to make it work well on Chrome, but doesn't work on Safari
= f.datagrid_filter :created_at, class: "form-control"
nested fields for generated twice
<%= form_for(@event) do |f| %>
<% @event.eventdistances.in_groups_of(6, false) do |eventdistances| %>
<div class='row'>
<%= f.fields_for :eventdistances, eventdistances do |eventdistance| %>
<div class='small-2 medium-2 large-2 columns'>
<%= eventdistance.check_box :active %> <%= eventdistance.object.building.nome %><br /><%= number_with_precision(eventdistance.object.distance, precision: 1) %> km
</div>
<% end %>
</div>
<% end %>
<% end %>
The first problem what that when you call f.fields_for :eventdistances do |eventdistance|
its calling f.object.eventdistances
(f.object = @event) and not using the local variable as you are expecting. Thats why it repeats all the records six times.
What you want to do is pass the collection as the second argument. Also if you want to put each group into a <div class='row'>
you want to place the tag inside the block passed to .in_groups_of
.
Rails - Why does my nested model form not require 'accepts_nested_attributes_for'
You don't need it because your pattern is wrong:
@user_item = @item.user_items.build(user_id: current_user.id, picture: item_params[:item][:picture])
With your above code, you're creating individual user_items
from each @item
. This does not require accepts_nested_attributes_for
, but is cumbersome, against convention and very hacky.
Here's how it should be done:
Models
#app/models/item.rb
class Item < ActiveRecord::Base
has_many :user_items
has_many :users, through: :user_items
accepts_nested_attributes_for :user_items
end
#app/models/user_item.rb
class UserItem < ActiveRecord::Base
belongs_to :user
belongs_to :item
end
Controllers
#app/controllers/items_controller.rb
class ItemsController < ApplicationController
def new
@item = Item.new
@item.user_items.build
end
def create
@item = Item.new item_params
redirect_to @item, notice: "Thank you for your item submission." if @item.save
end
private
def item_params
params.require(:item).permit(:name, :description, :tag_list, user_items_attributes: [:picture])
end
end
Views
#app/views/items/new.html.erb
<%= simple_form_for @item do |item_builder| %>
<%= item_builder.input :name, required: false, error: false, label: "Item name" %>
<%= item_builder.input :description, as: :text, required: false, error: false, label: "Describe item" %>
<%= item_builder.input :tag_list, required: false, label: "Tags" %>
<%= item_builder.simple_fields_for :user_items do |user_item_builder| %>
<%= user_item_builder.input :picture, as: :file, required: false, label: "Picture of you with this item" %>
<% end %>
<%= item_builder.submit 'Submit new item', class: "btn btn-primary pull-right inherit-width" %>
<% end %>
is there a problem with the way I'm doing it
Technically, no.
However, if you aspire to be a professional, or on a similar level, you'll not get very far with the code you wrote.
Using a framework like Rails gives you access to an unprecedented array of pre-baked functionality. The best code is not the code you wrote, but the library code that's been compiled & tested over years of production use.
Whilst your code works, it's not efficient nor extensible.
--
The ultimate key of whether what you've written is "right" is whether the future you would be proud of looking at it again. If not, you're probably best refactoring.
Update
If you want to give Item
a status
, you'll want to look at the enum
module for ActiveRecord models:
#app/models/item.rb
class Item < ActiveRecord::Base
enum status: [:active, :pending, :declined]
end
This is a very interesting method, as it provides a series of class methods (scopes), and instance methods:
@item = Item.find x
@item.active? #-> true
@item.pending? #-> false
@item.declined? #-> false
Item.active #-> collection of "active" items
Item.pending #-> collection of "pending" items
Item.declined #-> collection of "declined" items
To save an Item's status
, you could use the collection_select
as so:
<%= form_for @item do |f| %>
<%= f.collection_select :status, Item.statuses, :first, :first %>
<%= f.submit %>
<% end %>
Update
Your code can be improved massively:
def create
@item= Item.new item_params #-> this line should do ALL the heavy lifting.
if @item.save
redirect_to items_path, notice: "Thank you for your item request!"
else
render :new
end
end
private
def item_params
params.require(:item).permit(:name, :description, :tag_list, user_items_attributes: [:picture]).merge(created_by: current_user.id)
end
The file
field won't be populated again if you have validation issues; it's an OS problem, not Rails (how does the OS know your file is in the same location as it was when you first submitted?).
You need to make your create
code as succinct as possible; explicit declarations for attributes is generally a bad idea. You should put as much of it as possible into the Item
model (enum
etc).
Related Topics
Bootstrap Container with Position:Absolute Loses Layout Inside
Image Paths in CSS to Support Cdn
How to Use The .Clearfix Class
How to Make Leaflet Map Height Variable
CSS: Series of Floated Elements Without Wrapping But Rather Scrolling Horizontally
2-Column CSS Responsive Layout with a Responsive Image
How to Get a Custom Scroll in Firefox and Ie
How to Have Multiple Svg Images in a Single File
How to Make a Small Circle's Border Smooth
Calculating Square-Roots with CSS
Should You Use Rgba(0, 0, 0, 0) or Rgba(255, 255, 255, 0) for Transparency in CSS