Rails Bootstrap How to Format Form_For (Width Grid Collapses)

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



Leave a reply



Submit