I am a newbie in Rails. I am not understanding what I'm doing wrong here.
I have the following model order.rb, with a virtual attribute value:
class Order < ActiveRecord::Base
ACTIONS = %w(buy sell)
ORDER_TYPES = %w(LMT STP)
TIFS = %w(DAY GTC OPG IOC)
attr_accessible :action, :price, :quantity, :symbol, :tif, :order_type, :value
validates :action, :symbol, :tif, :order_type, presence: true
validates :price, numericality: { greater_than_or_equal_to: 0.0001 }
validates :quantity, numericality: { only_integer: true, greater_than: 0 }
validates :action, inclusion: ACTIONS
validates :order_type, inclusion: ORDER_TYPES
validates :tif, inclusion: TIFS
def value
price * quantity
end
def value= (val)
self.quantity = val / self.price
end
end
This model works fine in rails console, where I can set value and it calculates quantity.
The problem is when I try to visualize the form.
app/views/orders/new.html.erb renders the following _form.html.erb:
<%= form_for #order, html: { :class => 'form-inline' } do |f| %>
<% if #order.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#order.errors.count, "error") %> prohibited this order from being saved:</h2>
<ul>
<% #order.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<fieldset>
<legend><%= params[:action].capitalize %> Order</legend>
<table class="table">
<thead>
<tr>
<th><%= f.label :action %></th>
<th><%= f.label :symbol %></th>
<th><%= f.label :price %></th>
<th><%= f.label :value %></th>
<th><%= f.label :order_type %></th>
<th><%= f.label :tif, "TIF" %></th>
</tr>
</thead>
<tbody>
<tr>
<td><%= f.select :action, Order::ACTIONS, {}, class: 'input-small' %></td>
<td><%= f.text_field :symbol, class: 'input-small' %></td>
<td><%= f.text_field :price, class: 'input-small' %></td>
<td><%= f.text_field :value, class: 'input-small' %></td>
<td><%= f.select :order_type, Order::ORDER_TYPES, {}, class: 'input-small' %></td>
<td><%= f.select :tif, Order::TIFS, {}, class: 'input-small' %></td>
</tr>
</tbody>
</table>
<%= f.submit "Submit", class: "btn btn-primary" %>
<%= f.submit "Clear", class: "btn", type: "reset" %>
</fieldset>
<% end %>
I get an error when I open the page in the browser, raised on the line of _form.html.erb with the text field value:
NoMethodError in Orders#new
undefined method `*' for nil:NilClass
What am I doing wrong? I tried to follow http://railscasts.com/episodes/16-virtual-attributes
For the newly built order object price is nil. So you are getting this error.
Before calculating value make sure that you have price and quantity
def value
return unless price || quantity
price * quantity
end
Related
I linked the following two tables.
I want to send the written data from the form to two different tables and save it.
But I can't save too the child table.
I'm a beginner and I tried for two days.but I don't know.
Can you please help me?
bird table
id
name
breed
sex ...
bird_condition table
id
ave_weight
body_shape
...
(bigint "bird_id")
Version Rails 6.0.0
#app/models/bird.rb
class Bird < ApplicationRecord
has_many :bird_conditions, dependent: :destroy
accepts_nested_attributes_for :bird_conditions, allow_destroy: true :reject_bird_condition
end
#app/models/bird_condition.rb
belongs_to :bird, optional: true
end
#app/controllers/birds_controller.rb
class BirdsController < ApplicationController
before_action :set_bird,only: [:edit, :update, :destroy]
before_action :authenticate_user!
before_action :correct_user,only: [:edit, :destroy]
def index
#birds = current_user.birds.order(created_at: :desc)
end
def new
#bird = Bird.new
#bird.bird_conditions.build
end
def edit
end
def update
#bird.update!(bird_params)
redirect_to birds_path,notice: "upload"
end
def create
#bird = current_user.birds.new(bird_params)
if #bird.save
logger.debug "bird: #{#bird.attributes.inspect}"
redirect_to birds_path, notice: "create"
else
render :new
end
end
def destroy
#bird.destroy
redirect_to birds_path,notice: "delete"
end
private
def set_bird
#bird = current_user.birds.find(params[:id])
end
def correct_user
#bird = current_user.birds.find_by(id: params[:id])
redirect_to birds_path if #bird.nil?
end
def bird_params
params
.require(:bird)
.permit(
:name,
:breed_id,
:sex,
:birthday,
:personality,
:appeareance,
:srarus_flg,
:lost_day,
:lost_place,
:day_of_death,
:image,
bird_conditions_attributes:[
:id,
:ave_weight,
:body_shape,
:hospital,
:medical_history,
:medication,
:insurance,
:estrous_behavior,
:estrous_personality,
:bird_id
]
)
end
end
#app/views/birds/_form.html.erb
<div class="container">
<%= form_with model: bird, local: true do |f| %>
<table class="table-bordered">
<div class="form-group">
<tr>
<th><%= f.label :name %></th>
<td><%= f.text_field :name %></td>
</tr>
<tr>
<th><%= f.label :breed %></th>
<td><%= f.collection_select :breed_id, Breed.all, :id, :name, include_brank: 'select' %></td>
</tr>
〜〜〜〜〜〜〜〜〜〜〜〜abbreviation〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
<%= f.fields_for :bird_condition do |condition| %>
<%= render partial: 'form_condition', locals:{condition: condition}%>
<% end %>
</div><!-- .form-group -->
</table><br>
<%= f.submit nil, class: 'btn btn-primary'%>
<% end %>
</div><!-- .container -->
#app/views/birds/_form_condition.html.erb
<div class="form-group">
<tr>
<th><%= condition.label :ave_weight %></th>
<td><%= condition.number_field :ave_weight %></td>
</tr>
<tr>
<th><%= condition.label :body_shape %></th>
<td>
<%= condition.radio_button :body_shape, :medium %>
<%= condition.label :body_shape, :普通%>
<%= condition.radio_button :body_shape, :slim%>
<%= condition.label :body_shape, :痩せぎみ%>
<%= condition.radio_button :body_shape, :bony%>
<%= condition.label :body_shape, :痩せ%>
<%= condition.radio_button :body_shape, :chubby%>
<%= condition.label :body_shape, :太りぎみ%>
<%= condition.radio_button :body_shape, :fat%>
<%= condition.label :body_shape, :肥満%>
</td>
</tr>
<tr>
<th><%= condition.label :hospital %></th>
<td><%= condition.text_field :hospital %></td>
</tr>
<tr>
<th><%= condition.label :medical_history %></th>
<td><%= condition.text_field :medical_history %></td>
</tr>
<tr>
<th><%= condition.label :medication %></th>
<td><%= condition.text_field :medication %></td>
</tr>
<tr>
<th><%= condition.label :insurance %></th>
<td><%= condition.text_field :insurance %></td>
</tr>
<tr>
<th><%= condition.label :estrous_behavior %></th>
<td><%= condition.text_field :estrous_behavior %></td>
</tr>
<tr>
<th><%= condition.label :estrous_personality %></th>
<td><%= condition.text_field :estrous_personality %></td>
</tr>
</div><!-- .form-group -->
#error(log)
Unpermitted parameter: :bird_condition
In your form you have :bird_condition but in your params you have bird_conditions_attributes ... you just need to adjust the params in your controller:
def bird_params
params
.require(:bird)
.permit(
:name,
...
bird_conditions: [ # Use `bird_conditions` here.
:id,
...
]
)
end
So what I have is a model Referent that has multiple attributes for example nom and prenom.
I was able to search each attribute in my model using one search value. But then I tried having one text_field for each attribute so for nom I would have one text_field and for prenom I would have another.
So it would search for all Referent who have that nom and that prenom but I'm not capable of seperating those two search. Right now it just take one of the value and search in both nom and prenom with the same value
View:
<h2>Search Referent</h2>
<%= form_tag(referents_path, :method => "get", id: "search-form") do %>
<%= text_field_tag :search, params[:search], placeholder: "Nom" %>
<%= text_field_tag :search, params[:search], placeholder: "Prenom" %>
<%= submit_tag "Search", class: 'btn btn-info' %>
<% end %>
Controller:
def index
#referents = Referent.all
if params[:search]
#referents = Referent.search(params[:search]).order("created_at DESC")
else
#referents = Referent.all.order("created_at DESC")
end
end
Model:
def self.search(search)
where("nom || prenom ILIKE ?", "%#{search}%")
end
Right now it just seems to take the value of the second text_field and use that for the search. I'm using postgresql.
The full view:
<div class="container">
<h2>Search Referent</h2>
<%= form_tag(referents_path, :method => "get", id: "search-form") do %>
<%= text_field_tag :search_nom, params[:search], placeholder: "Nom" %>
<%= text_field_tag :search_prenom, params[:search], placeholder: "Prenom" %>
<%= submit_tag "Search", class: 'btn btn-info' %>
<% end %>
<h2>List de Referent</h2>
<table class="table table-hover">
<tr>
<th>Nom</th>
<th>Prenom</th>
<th>Titre</th>
<th>Departement</th>
<th>Cellulaire</th>
<th>Bureau</th>
<th>Fax</th>
<th>Courriel</th>
<th>Organisme Referent</th>
</tr>
<% #referents.each do |referent| %>
<tr>
<td><%= referent.nom %></td>
<td><%= referent.prenom %></td>
<td><%= referent.titre %></td>
<td><%= referent.departement %></td>
<td><%= referent.cellulaire %></td>
<td><%= referent.bureau %></td>
<td><%= referent.fax %></td>
<td><%= referent.courriel %></td>
<td><%= link_to referent.organismereferent.nom_organisation, organismereferent_path(referent.organismereferent_id) %></td>
</tr>
<% end %>
</table>
</div>
Error using Ramon answer
I would do it like this
<h2>Search Referent</h2>
<%= form_tag(referents_path, :method => "get", id: "search-form") do %>
<%= text_field_tag :search_nom, params[:search_nom], placeholder: "Nom" %>
<%= text_field_tag :search_prenom, params[:search_prenom], placeholder: "Prenom" %>
<%= submit_tag "Search", class: 'btn btn-info' %>
<% end %>
Controller
def index
#referents = Referent.all
search_nom = params[:search_nom]
search_prenom = params[:search_prenom]
#referents = Referent.search(search_nom, search_prenom).order("created_at DESC")
end
Model
def self.search(search_nom, search_prenom)
where("nom ILIKE ? or prenom ILIKE ?", "%#{search_nom}%", "%#{search_prenom}%")
end
I'm trying to save a recurring_select to a serialized attribute to handle recurring events on a rails app.
Using Jayson's post I manage to get the schedule saved but now I can't get the saved
attribute shown in index view or update the recurring_select in _form view
This is my model
class Todo < ActiveRecord::Base
attr_accessible :item, :completed, :schedule, :start_date
after_initialize :default_values
validates :item, presence: true
belongs_to :list
belongs_to :tasklib,
:foreign_key=>"item"
#recuring model
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :schedule
serialize :schedule, Hash
def schedule=(new_schedule)
write_attribute(:schedule,RecurringSelect.dirty_hash_to_rule(new_schedule).to_hash)
end
def converted_schedule
the_schedule = Schedule.new(self.start_date)
the_schedule.add_recurrence_rule(RecurringSelect.dirty_hash_to_rule(self.schedule))
the_schedule
end
end
This is my index view :
h1><%= #list.name %></h1>
<table class="table table-striped">
<thead>
<tr>
<th><%= model_class.human_attribute_name(:item) %></th>
<th><%= model_class.human_attribute_name(:start_date) %></th>
<th><%= model_class.human_attribute_name(:schedule) %></th>
<th><%=t '.actions', :default => t("helpers.actions") %></th>
</tr>
</thead>
<tbody>
<% #list.todos.each do |todo| %>
<tr>
<td><%= todo.item %></td>
<td><%= todo.start_date %></td>
<td><%= todo.schedule %></td>
<td>
<%= link_to t('.edit', :default => t("helpers.links.edit")),
edit_list_todo_path(#list, todo), :class => 'btn btn-mini' %>
<%= link_to t('.destroy', :default => t("helpers.links.destroy")),
list_todo_path(#list, todo),
:method => :delete,
:confirm => t('.confirm', :default => t("helpers.links.confirm", :default => 'Are you sure?')),
:class => 'btn btn-mini btn-danger' %>
</td>
</tr>
<% end %>
</tbody>
</table>
and this is my _form view:
<%= simple_form_for [#list, if #todo.nil? then #list.todos.build else #todo end], :html => { :class => 'form-horizontal' } do |f| %>
<%-# f.input :item, input_html: {class: "span6", rows: 3} -%>
<%= f.collection_select :item, Tasklib.order(:name),:name,:name, include_blank: true %>
<%= f.label :start_date, "date" %>
<%= f.input :start_date %>
<%= f.label :schedule %>
<%= f.select_recurring :schedule, nil, :allow_blank => true %>
<div class="form-actions">
<%= f.submit 'Save', :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
lists_path, :class => 'btn' %>
</div>
<% end %>
OK I found it !
The model should be :
def schedule=(new_schedule)
if new_schedule == nil
new_schedule = IceCube::Schedule.new( self.start_date )
end
write_attribute(:schedule, RecurringSelect.dirty_hash_to_rule(new_schedule).to_hash)
end
def converted_schedule
if !self.read_attribute(:schedule).empty?
the_schedule = IceCube::Schedule.new( self.start_date )
the_rule = RecurringSelect.dirty_hash_to_rule( self.read_attribute(:schedule) )
if RecurringSelect.is_valid_rule?(the_rule)
the_schedule.add_recurrence_rule( the_rule)
end
the_schedule
end
end
and the form view should only set a new recurring select like:
<%= f.select_recurring :schedule, [ ["No recurring", "{}"] ], :allow_blank => true %>
my controller:
class SetupsController < ApplicationController
def new
#setup = Setup.new
#todays_rate = #setup.todays_rates.build
end
def create
#setup = Setup.new(params[:setup])
if #setup.save
redirect_to setup_path(#setup)
else
render 'new'
end
end
end
My view code: setup/new.html.erb
<%= form_for #setup, :html => {:multipart => true} do |f| %>
<% if #setup.errors.any? %>
<ul>
<% #setup.errors.full_messages.each do |error| %>
<li><strong><%= error %></strong></li>
<% end %>
</ul>
<% end %>
<h4><%= f.label :effective_from, class:'required' %>
<%= f.text_field :effective_from %></h4>
<h4><%= f.label :effective_to, class:'required' %>
<%= f.text_field :effective_to %></h4>
<%= f.fields_for(:todays_rate) do |i| %> ##**combining two model with one view**
<h1>Interest Rate</h1>
<table cellpadding = "5px" cellspacing = "5px" width = "100%" class="table condensed-table"><tr>
<h4><th>Days From</th>
<th>Days To</th>
<th>Rate</th>
<th>Senior increment</th>
<th>Super Senior increment</th>
<th>Widow increment</th></h4>
</tr>
<h4><td><%= i.text_field :days_from, :class => 'input-mini' %></td></h4>
<h4> <td><%= i.text_field :days_to, :class => 'input-mini' %></td></h4>
<h4><td><%= i.text_field :rate, :class => 'input-mini' %></td></h4>
<h4> <td><%= i.text_field :senior_increment, :class => 'input-mini' %></td></h4>
<h4> <td><%= i.text_field :super_senior_increment,class:"input-mini" %></td></h4>
<h4><td><%= i.text_field :widow_incrtement,class: "input-mini" %></td></h4>
</table>
<% end %>
<fieldset class="form-actions"> <%= f.submit "Create Customer", class: "btn btn-primary" %></field>
setup.rb mmodel:
class Setup < ActiveRecord::Base
has_many :todays_rates
accepts_nested_attributes_for :todays_rates
attr_accessible :effective_from, :effective_to, :todays_rate
end
i'm combining two model in one view but i'm getting the above error. i don't know where i missed the keyword_end.can any one help me
I think your problem is that you haven't closed the form, ie you need a <% end %> at the end of your template.
The error sort of tells you that, though the tIDENTIFIER stuff can throw one off the scent a bit.
First of all sorry about my English and about my knowledge of Rails, I am beginner who just started.
I have 2 models with relations:
CargoItems:
class CargoItem < ActiveRecord::Base
belongs_to :cargo
attr_accessible :cargo_id, :height, :length, :pieces, :weight, :width
validates :cargo, :height, :length, :width, :weight, :pieces, presence: true
validates :height, :length, :width, :pieces, numericality: { only_integer: true, greater_than_or_equal_to: 1}
validates :weight, numericality: { only_integer: true, greater_than_or_equal_to: 100}
end
Cargos:
class Cargo < ActiveRecord::Base
belongs_to :airport
belongs_to :user
belongs_to :cargo_state
belongs_to :cargo_price
belongs_to :cargo_description
has_many :cargo_items, :inverse_of => :cargo, :dependent => :destroy
attr_accessible :departure_date, :cargo_state_id, :airport_id, :cargo_price_id, :cargo_description_id, :cargo_items_attributes
accepts_nested_attributes_for :cargo_items, :allow_destroy => true, :reject_if => :all_blank
validates_associated :cargo_items
validates :departure_date, :cargo_state, :airport, :cargo_price, :cargo_description, presence: true
validates :departure_date, date: { after: Proc.new { Date.today - 1.day }, before: Proc.new { Time.now + 1.year } }, :on => :create
default_scope :order => 'departure_date DESC'
end
I use following GEMs: simple_forms, nested_forms. This is form to add new Cargo with multiple CargoItems (they have possibility to be added dynamically) belonging to Cargos:
<%= simple_nested_form_for #cargo, :wrapper => false do |f| %>
<%= f.association :airport, :label_method => :full_airport_name, :value_method => :id , :order => :iata_code %>
<%= f.input :departure_date , as: :date, start_year: Date.today.year,
end_year: Date.today.year + 16,
order: [:day, :month, :year] %>
<%= f.association :cargo_description, :label_method => :description, :value_method => :id, :order => :description %>
<%= f.association :cargo_price, :label_method => :price, :value_method => :id %>
<%= f.association :cargo_state, :label_method => :state, :value_method => :id %>
<hr>
<table>
<tr>
<th><%= :length %></th>
<th><%= :width %></th>
<th><%= :height %></th>
<th><%= :weight %></th>
<th><%= :pieces %></th>
</tr>
<%= f.simple_fields_for :cargo_items, #cargo_item do |cargo_items_fields| %>
<tr class="fields">
<td><%= cargo_items_fields.text_field :length %></td>
<td><%= cargo_items_fields.text_field :width %></td>
<td><%= cargo_items_fields.text_field :height %></td>
<td><%= cargo_items_fields.text_field :weight %></td>
<td><%= cargo_items_fields.text_field :pieces %></td>
<td><%= cargo_items_fields.link_to_remove "Remove this item", :confirm => 'Are you sure you want to remove this item?' %></td>
</tr>
<% end %>
</table>
<%= f.link_to_add "Add a item", :cargo_items %>
<div class="actions">
<%= f.button :submit %>
</div>
<% end %>
Cargo controller:
def new
#cargo = Cargo.new
#cargo_item = CargoItem.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #cargo }
end
end
def create
#cargo = Cargo.new(params[:cargo])
#cargo.user_id = current_user[:id]
respond_to do |format|
if #cargo.save
format.html { redirect_to #cargo, notice: 'Cargo was successfully created.' }
format.json { render json: #cargo, status: :created, location: #cargo }
else
format.html { render action: "new" }
format.json { render json: #cargo.errors, status: :unprocessable_entity }
end
end
end
My problem is, validation errors are not shown for CargoItems, model is actually validating. I am not able to save Cargos with CargoItems which does not fulfill validating rules. But in case validations are not met, Cargo is not saved and it just stayed on the same page without any notification that CargoItems fields are invalid. Cargos fields validation errors are shown properly.
Thanx a lot for helping me.
You need to add this errors notication before your form. Take a look at mine for example
<% if #author.errors.any? %>
<div class="alert alert-block">
<ul>
<% #author.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<% if #book.errors.any? %>
<div class="alert alert-block">
<ul>
<% #book.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= form_for([#author, #book], html: { class: "well" }) do |f| %>
#labels and buttons...
<% end %>
I have an Author who has many Books, like so:
Author:
class Author < ActiveRecord::Base
attr_accessible :name
has_many :books, dependent: :destroy
accepts_nested_attributes_for :books, allow_destroy: true
validates :name, presence: true
validates :name, length: { minimum: 3 }
end
Book:
class Book < ActiveRecord::Base
attr_accessible :name, :year
belongs_to :author
validates :name, :year, presence: true
validates :year, numericality: { only_integer: true, less_than_or_equal_to: Time.now.year }
end
Simple Form also allows you to use label, hint, input_field, error and full_error helpers. for more detail documentation --> https://github.com/plataformatec/simple_form
Example code with error,
<%= simple_form_for #user do |f| %>
<%= f.label :username %>
<%= f.input_field :username %>
<%= f.hint 'No special characters, please!' %>
<%= f.error :username, id: 'user_name_error' %>
<%= f.full_error :token %>
<%= f.submit 'Save' %>
<% end %>