I am trying to make a nested form with two types of movements: mov_principal and mov_egreso, of which I try it through a main movement
these are the models
mov_principal.rb
class MovPrincipal < ActiveRecord::Base
self.table_name = 'mov_principal'
has_one :mov_ingreso, :class_name => 'MovIngreso'
accepts_nested_attributes_for :mov_ingreso
belongs_to :tipo_concepto, :class_name => 'TipoConcepto', :foreign_key => :id_tipo
belongs_to :banco
end
mov_ingreso
class MovIngreso < ActiveRecord::Base
self.table_name = 'mov_ingreso'
belongs_to :mov_principal , :class_name => 'MovPrincipal'
accepts_nested_attributes_for :mov_principal, :allow_destroy => true
has_many :puntos, :class_name => 'Punto'
end
the controller mov_principal_controller.rb
class MovPrincipalsController < ApplicationController
before_action :set_movprincipal, except: [:index,:new,:create]
before_action :set_tipooper
def index
#mov_principals = MovPrincipal.all.order("referencia DESC")
end
def new
#mov_principal = MovPrincipal.new
if params[:tipooper] == '0'
#mov_ingreso = #mov_principal.build_mov_ingreso
else
# #gastos = Gasto.new
# #mov_egresos = #mov_principal.build_mov_egresos
#mov_egresos = #mov_principal.mov_egresos.build
#gasto = #mov_egresos.build_gasto
end
end
def create
if #tipooper == '0'
#mov_principal = current_user.mov_principals.new(movingreso_params)
else
#mov_principal = current_user.mov_principals.new(movgastos_params)
end
if #mov_principal.save
render :show
else
render :new
end
end
private
def set_movprincipal
#mov_principal = MovPrincipal.find(params[:id])
end
def set_tipooper
#tipooper = params[:tipooper]
end
def movgastos_params
params.require(:mov_principal).permit(:id,:referencia,:id_tipo,:banco_id,
mov_egreso_attributes: [:id,:mov_principal_id,:haber, :gasto_id,
gasto_attributes: [Gasto.attribute_names.map(&:to_sym).push(:_destroy)]] )
end
def movingreso_params
params.require(:mov_principal).permit(:id,:referencia,:id_tipo,:banco_id,:user_id,:_destroy,
mov_ingreso_attributes: [:id,:debe,:mov_principal_id,:_destroy ])
end
end
And the view
_formingreso.html.erb
<%=form_for(#mov_principal, :html => {:class => 'form-horizontal'}) do |f| %>
<% #mov_principal.errors.full_messages.each do |message| %>
<div class="be-red white top-space">
* <%= message %>
</div>
<% end %>
<div class="form-group row">
<label class="col-sm-2 col-form-label"> <%= f.label :referencia, "N° Referencia" %> </label>
<div class="col-sm-10">
<%= f.text_field :referencia, class: 'form-control', placeholder: "N° DE REFERENCIA" %>
</div>
</div>
<div class="form-group row" >
<label class="col-sm-2 col-form-label"> <%= f.label :id_tipo, "Tipo" %> </label>
<div class="col-sm-10">
<%= f.collection_select(:id_tipo, TipoConcepto.where(:forma => "1"), :id, :tipo,{:prompt => "SELECCIONE EL TIPO DE INGRESO"}, {class: 'custom-select'}) %>
</div>
</div>
<div class="form-group row" >
<label class="col-sm-2 col-form-label"> <%= f.label :id_banco, "Banco" %> </label>
<div class="col-sm-10">
<%= f.collection_select(:banco_id, Banco.all, :id, :nombre,{:prompt =>"SELECCIONE EL BANCO"} ,{class: 'custom-select'} ) %>
</div>
</div>
<div class="form-group row" >
<%= f.fields_for :mov_ingreso_attributes do |ingreso| %>
<label class="col-sm-2 col-form-label"> <%= ingreso.label :debe, "Monto" %> </label>
<div class="col-sm-10">
<%= ingreso.text_field :debe, class: 'form-control' , placeholder: "MONTO DE INGRESO" %>
</div>
<% end %>
The page loads me, it saves me the mov_principal data but it does not save me the mov_ingreso data and the error I find in the console is Unpermitted parameter: :mov_ingreso_attributes
Please do not send me links from the official rails page on how to work strong_parameter blah blah blah I have hours researching and searching in forums trying solutions and even read in a blog about an error that has rails when updating version, and had to create a initializer of strong_parameter, I did it and nothing anyway I show it here just in case it has any relevance
/initializers/strong_parameter.rb
if Rails.env.test?
ActionController::Parameters.action_on_unpermitted_parameters = :raise
end
Thank you all!!
Related
I have a site where uses have a profile and can add an art to their profile and the month_started, year_started, and rank in that art. I am able to add the art but I cannot get update to work. I'm doing it from within the users folder on the show page. I render the add_art form on the profile page and it submits to the user_arts_controller's create action. For edit_art I am trying to use the edit.html.erb page inside users and it pulls in the information from the #art_user table to populate the fields, but when I submit it acts like it's updating and goes back to the set page and gives a success message but nothing gets updated. I used byebug and it shows all the params but says permitted: false.
Here is my form:
<% vars = request.query_parameters %>
<% #add = vars['add'] %>
<% if #add == "1" %>
<% art = "Judo" %>
<% else %>
<% art = "Brazillian Jiu Jitsu" %>
<% end %>
<div class="container">
<div class="row center form">
<div class="col-sm-12 col-md-10">
<div class="card-panel">
<h3>Edit <%= art %> info.</h3>
<%= form_with(model: #art, url: art_edit_path(art_id: #add), class: "shadow p-3 mb-3 rounded text-dark", local: true) do |f| %>
<div class="form-group row">
<div class="col-md-3 col-sm-12 col-form-label">
<%= f.label :month_started %>:<span class="text-danger">*</span>
</div>
<div class="col-md-9 col-sm-12">
<%= f.select :month_started, Date::MONTHNAMES[1..12], {prompt: true}, {class: 'form-control'} %>
</div>
</div>
<diva class="form-group row">
<div class="col-md-3 col-sm-12 col-form-label">
<%= f.label :year_started %>:<span class="text-danger">*</span>
</div>
<div class="col-md-9 col-sm-12">
<%= f.select :year_started, Date.today.year-70 .. Date.today.year, {prompt: true, order: [:year]}, {class: 'form-control'} %>
</div>
</diva>
<% #rank = Rank.where(art_id: #add) %>
<div class="form-group row">
<div class="col-md-3 col-sm-12 col-form-label">
<%= f.label :rank %>:<span class="text-danger">*</span>
</div>
<div class="col-md-9 col-sm-12">
<%= f.collection_select :rank_id, #rank, :id, :rank, {:prompt=>true}, {:class=>'form-control'} %>
</div>
</div>
<div class="form-group row text-right">
<div class="col-md-8 col-sm-12"></div>
<div class="col-md-4 col-sm-12">
<%= f.submit (#add == "1" ? "Edit Judo" : "Edit Brazilian Jiu Jitsu"), class: "profile_btn" %>
</div>
</div>
<% end %>
</div>
</div>
</div>
</diva>
Here is the user_arts_controller.rb:
class UserArtsController < ApplicationController
def create
art_to_add = Art.find(params[:art_id])
unless current_user.arts.include?(art_to_add)
UserArt.create(art: art_to_add, user: current_user, month_started: params["month_started"], year_started: params["year_started"], rank_id: params["rank_id"])
flash[:notice] = "You have successfully enrolled in #{art_to_add.art}"
redirect_to ("/users/#{current_user.username}?cat=comp")
else
flash[:notice] = "Something went wrong!"
redirect_to ("/users/#{current_user.username}")
end
end
def edit
#art = UserArt.find_by(user_id: current_user.id, art_id: 1)
if #art
#my_rank = Rank.find(id: #art.rank_id)
end
end
def update
byebug
#user_art = UserArt.where(id: params[:id])
if #user_art.update(art_params)
flash[:notice] = "You have successfully updated your art"
redirect_to ("/users/#{current_user.username}?cat=comp")
else
flash[:notice] = "Something went wrong!"
redirect_to ("/users/#{current_user.username}")
end
end
private
def art_params
params.require(:user_arts).permit(:user_id, :art_id, :month_started, :year_started, :rank_id)
end
end
Here are my routes:
Rails.application.routes.draw do
devise_for :users, controllers: { registrations: 'registrations', omniauth_callbacks: 'users/omniauth_callbacks' }
root 'pages#index'
get 'events', to: 'pages#events'
get 'features', to: 'pages#features'
get 'pricing', to: 'pages#pricing'
get 'about', to: 'pages#about'
get 'contact', to: 'pages#contact'
get 'privacy', to: 'pages#privacy'
get 'terms', to: 'pages#terms'
get 'remove', to: 'pages#remove'
delete 'logout', to: 'sessions#destroy'
resources :users, except: [:new], param: :username
resources :clubs, param: :club_username
post 'club_join', to: 'user_clubs#create'
post 'art_add', to: 'user_arts#create'
post 'art_edit', to: 'user_arts#edit'
patch 'art_edit', to: 'user_arts#update'
end
Here is what I get when I use byebug and enter params:
(byebug) params
<ActionController::Parameters {"_method"=>"patch", "authenticity_token"=>"UY4RG1D0N0IHcJeyftn44WmAgsdslKJScD+GSJPbAUEEjlJLiYLd2htK4RBTfrP+YPUXP5EFB5pQc98OmQPPtg==", "user_art"=>{"month_started"=>"January", "year_started"=>"1988", "rank_id"=>"14"}, "commit"=>"Edit Judo", "art_id"=>"1", "controller"=>"user_arts", "action"=>"update"} permitted: false>
(byebug)
Any help is greatly appreciated.
Thanks
I think you have an extra s in the definition of your allowed params. Since you are getting this:
"user_art"=>{"month_started"=>"January", "year_started"=>"1988", "rank_id"=>"14"}
You should check in this way:
def art_params
params.require(:user_art).permit(:user_id, :art_id, :month_started, :year_started, :rank_id)
end
Just a final comment. Take a look at the params you're permitting, I guess user_id shouldn't be one of them.
Let me know if it works
in Main form
<%= p.fields_for :prd_allisland_flat_deliveries do |i| %>
<%= render(:partial => 'prd_allisland_flat_delivery_field', :locals => {:f => i})%>
<% end %>
in the prd_allisland_flat_delivery_field form partial
<div class="row" style="padding-bottom: 25px">
<div class="col-md-2"></div>
<div class="col-md-4">
<%= f.label :delivery_period %>
</div>
<div class="col-md-4">
<%= f.text_field(:delivery_period, {placeholder: '0', class: 'form-control input_border input_field_text_align_right'})%>
</div>
<div class="col-md-2"></div>
</div>
<div class="row" style="padding-bottom: 25px">
<div class="col-md-2"></div>
<div class="col-md-4">
<%= f.label :delivery_rate %>
</div>
<div class="col-md-4">
<%= f.text_field(:delivery_rate, {placeholder: 'Rs. 0.00', class: 'form-control input_border input_field_text_align_right'})%>
</div>
</div>
in prd_item controller
**def new
#item = PrdItem.new
#item.build_prd_allisland_flat_delivery
end**
after writing this the create method
**
if #item.save
if #item.delivery_type == 1
#all_island_flat = PrdAllislandFlatDelivery.new(item_params[:prd_allisland_flat_deliveries_attributes])
#all_island_flat.save
end
end**
the item_params
def item_params
params.require(:prd_item).permit(:item_name, :brand, :item_no, :short_description, :long_description, :prd_type_id, :usr_vendor_property_id, :price,:base_price, :price_discount, :percentage_discount, :stock_count, :availability, :tags, :remove_image, :delivery_type , :min_stock_count,
prd_item_images_attributes: [:id, :image, :description, :link, :_destroy ],
prd_temp_variation_stores_attributes: [:id, :product_variations, :variation_items, :_destroy],
prd_temp_compound_stores_attributes:[:id,:compound, :compound_item, :_destroy],
prd_temp_spec_stores_attributes:[:id,:compound, :compound_item, :_destroy],
prd_allisland_flat_deliveries_attributes: [:id,:delivery_period,:delivery_rate],
prd_province_vise_deliveries_attributes: [:id , :province_name , :delivery_rate, :delivery_period]
)
end
the rails consoler gets the attributes for the prd_allisland_flat_deliveries but the prd_all_island_flat_deliveries fill with null values
Is that your full create method? If so you need to understand that every request is separate from others, the create request doesn't know what happened in the new request.
In your create method you need to build your basic object, then update the object from the params.
def create
#item = PrdItem.new
#item.update(item_params)
if #item.save ...
I am trying to make a new Deliverable which has nested DeliverableDates. The Deliverable's attributes, such as title, save but the nested attributes in DeliverableDates don't. What am I missing?
Many Thanks
class ProgramManager::DeliverablesController < ProgramManager::ApplicationController
...
def new
#deliverable = #program.deliverables.build
#program.groups.each do |group|
#deliverable.deliverable_dates.build(group_id: group.id)
end
clean_deliverables
3.times { #deliverable.select_options.build }
end
def create
delete_empty_select_options
#deliverable = #program.deliverables.new(params[:deliverable])
clean_deliverables
if #deliverable.save
redirect_to program_deliverables_path(#program), success: 'Deliverable created successfully'
else
#program.groups.each do |group|
#deliverable.deliverable_dates.build(group_id: group.id)
end
render :new
end
end
...
end
-
<%= form_for [#program, deliverable], html: { class: 'form-horizontal' } do |f| %>
<%= render 'shared/error_messages', object: deliverable %>
...
<div class="in-out <%= "hidden" if deliverable.is_by_date? %>" id="in-out">
<%= f.fields_for :deliverable_dates do |d| %>
<h5><%= Group.find(d.object.group_id).name %></h5>
<div class="form-group">
<%= d.label :in_date, 'In Date', class: 'col-md-2 control-label' %>
<div class="col-md-10">
<%= d.text_field :in_date, class: 'form-control input-sm datepicker', id: 'deliverable_in_date_new', placeholder: 'In Date' %>
</div>
</div>
<div class="form-group">
<%= d.label :out_date, 'Out Date', class: 'col-md-2 control-label' %>
<div class="col-md-10">
<%= d.text_field :out_date, class: 'form-control input-sm datepicker', id: 'deliverable_out_date_new', placeholder: 'Out Date' %>
</div>
</div>
<% end %>
</div>
...
<div class="form-group">
<div class="col-md-10 col-md-offset-2">
<%= f.submit 'Save changes', class: 'btn btn-primary' %>
</div>
</div>
<% end %>
-
class Deliverable < ActiveRecord::Base
include Folderable
include Reportable
attr_accessible :program_id, :deliverable_type, :is_by_date, :title, :file_cabinet_folder, :select_options_attributes
attr_accessor :in_data_cell, :out_data_cell, :by_data_cell
belongs_to :program
has_many :deliverable_dates, dependent: :destroy
has_many :select_options, as: :optionable, dependent: :destroy
has_many :deliverable_data, dependent: :destroy
has_many :folders, as: :folderable, dependent: :destroy
delegate :in_date, :out_date, :by_date, to: :deliverable_dates
accepts_nested_attributes_for :select_options, allow_destroy: true
accepts_nested_attributes_for :deliverable_dates, allow_destroy: true
...
end
-
class DeliverableDate < ActiveRecord::Base
attr_accessible :group_id, :deliverable_id, :in_date, :out_date, :by_date
belongs_to :group
belongs_to :deliverable
validates :group_id, presence: true
validates :deliverable_id, presence: true
scope :past_due, -> { where('(out_date is not null and out_date < ?) or (by_date is not null and by_date < ?)', Date.today, Date.today) }
scope :upcoming, -> { where('((in_date is not null and in_date >= ?) and (out_date is not null and out_date >= ?)) or (by_date is not null and by_date >= ?)', Date.today, Date.today, Date.today) }
scope :current_deliverables, -> { where('((by_date > ? and by_date <= ?) or (in_date > ? and in_date <= ?) or (out_date > ? and in_date <= ?) or (in_date >= ? and out_date <= ?))', Date.today, 10.days.from_now, Date.today, 5.days.from_now, Date.today, 5.days.from_now, Date.today, Date.today) }
end
In order to make the 'accepts_nested_attributes_for' work properly ":deliverable_dates_attributes" must be added to the attr_accessible for the Deliverable
I'm having a huge problem here with Rails. The thing is, that I have 32 models that are associated with one main model.
The model is called Problem - each problem has a leveloneeffect, levelonecause, leveloneend, leveloneway.
Now each of the previous level, has another models associated with them like leveltwoeffect is associated with leveloneeffect and so on..
Each model is correctly associated with other and the form shows all the label and texfields correctly to submit; but when I do submit I get the following error:
Can't mass-assign protected attributes: levelonecause_id
app/controllers/problems_controller.rb:27:in `update'
Now in the controller I have the follow code in the 27 line
def update
#problem = Problem.find(params[:id])
#problem.update_attributes(params[:problem]) <--- LINE 27
flash[:notice] = "Programa editado correctamente."
redirect_to edit_problem_path(#problem)
end
Any ideas?
Here is my problemcontroller
def index
#problem = Problem.all
end
def new
#problem = Problem.new
end
def create
#problem = Problem.new(params[:problem])
#problem.user_id = current_user.id
#problem.save
flash[:notice] = "Prorgrama Creado."
redirect_to edit_problem_path(#problem)
end
def show
#problem = Problem.find(params[:id])
end
def edit
#problem = Problem.find(params[:id])
end
def update
#problem = Problem.find(params[:id])
#problem.update_attributes(params[:problem])
flash[:notice] = "Programa editado correctamente."
redirect_to edit_problem_path(#problem)
end
def destroy
#problem = Problem.find(params[:id])
#Problem.destroy
flash[:notice] = "Programa borrado correctamente."
redirect_to problems_path
end
end
Add here is the problem model
attr_accessible :leveltwocause_attributes,:indicator_attributes, :leveloneeffect_attributes, :levelonecause_attributes, :budget_program, :city, :department, :email, :name, :responsable_unit, :init_date, :end_date, :organism, :definition, :idea_attributes
belongs_to :user
has_many :idea
has_many :levelonecause
has_many :leveltwocause, :through => :levelonecause
has_many :levelthreecause, :through => :leveltwocause
has_many :levelfourcause, :through => :levelthreecause
has_many :levelfivecause, :through => :levelfourcause
has_many :levelsixcause, :through => :levelfivecause
has_many :levelsevencause, :through => :levelsixcause
has_many :leveleightcause, :through => :levelsevencause
has_many :indicator
has_many :leveloneeffect
has_many :leveltwoeffect, :through => :leveloneeffect
has_many :levelthreeeffect, :through => :leveltwoeffect
has_many :levelfoureffect, :through => :levelthreeeffect
has_many :levelfiveeffect, :through => :levelfoureffect
has_many :levelsixeffect, :through => :levelfiveeffect
has_many :levelseveneffect, :through => :levelsixeffect
has_many :leveleighteffect, :through => :levelseveneffect
accepts_nested_attributes_for :idea, :allow_destroy => true
accepts_nested_attributes_for :levelonecause, :allow_destroy => true
accepts_nested_attributes_for :leveltwocause, :allow_destroy => true
accepts_nested_attributes_for :levelthreecause, :allow_destroy => true
accepts_nested_attributes_for :levelfourcause, :allow_destroy => true
accepts_nested_attributes_for :levelfivecause, :allow_destroy => true
accepts_nested_attributes_for :levelsixcause, :allow_destroy => true
accepts_nested_attributes_for :levelsevencause, :allow_destroy => true
accepts_nested_attributes_for :leveleightcause, :allow_destroy => true
accepts_nested_attributes_for :leveloneeffect, :allow_destroy => true
accepts_nested_attributes_for :leveltwoeffect, :allow_destroy => true
accepts_nested_attributes_for :levelthreeeffect, :allow_destroy => true
accepts_nested_attributes_for :levelfoureffect, :allow_destroy => true
accepts_nested_attributes_for :levelfiveeffect, :allow_destroy => true
accepts_nested_attributes_for :levelsixeffect, :allow_destroy => true
accepts_nested_attributes_for :levelseveneffect, :allow_destroy => true
accepts_nested_attributes_for :leveleighteffect, :allow_destroy => true
accepts_nested_attributes_for :indicator, :allow_destroy => true
end
Here is the form
<%= simple_nested_form_for #problem, :html => { :class => " widgetbox box-inverse form-horizontal" } do |f| %>
<div class="tabbable"> <!-- Only required for left/right tabs -->
<ul class="nav nav-pills">
<li class="active">Definicion del Problema</li>
<li>Arbol del Problema</li>
<li>Arbol de Objetivos</li>
<li>Matriz Marco Logico</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade in active" id="definicion">
<ul class="nav nav-tabs">
<li>Informacion Basica</li>
<li>Definicion del Problema</li>
<li>Lluvia de Ideas</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade" id="infbasica">
<div class="span4 offset1">
<%= f.input :name, label: 'Nombre del Programa' %>
<%= f.input :organism, label: 'Dependencia', collection: ["Dependencia 1", "Dependencia 2", "Dependencia 3"] %>
<%= f.input :responsable_unit, label: 'Nombre del Responsable del Programa' %>
<%= f.input :city, label: 'Ciudad', collection: [ "Chihuahua", "DF", "Toluca", "Juarez"] %>
<%= f.input :department, label: 'Departamento', :collection => [ "Direccion Tecnica", "Proyectos Especiales", "Sub Direccion de Estudios"] %>
<%= f.input :email, label: 'Correo Electronico', placeholder: 'usuario#correo.com' %>
</div>
<div class="span4 offset1">
<%= f.input :init_date, label: 'Fecha problable de Inicio'%>
<%= f.input :end_date, label: 'Fecha problable de Terminacion' %>
</div>
</div>
<div class="tab-pane fade" id="nombrar">
<div class="span6 offset1">
<%= f.input :definition, label: 'Definicion del Problema', as: :text %>
</div>
</div>
<div class="tab-pane fade" id="lluvia">
<div class="span6 offset1">
<%= f.simple_fields_for :idea do |i| %>
<%= i.input :content, label: 'Idea', as: :text, required: false %>
<%= i.link_to_remove "Quitar", :class => 'btn btn-danger' %>
<% end %>
<%= f.link_to_add "Agregar Idea", :idea %>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="arbolproblema">
<ul class="nav nav-tabs">
<li>Causas</li>
<li>Efectos</li>
<li>Generar Diagrama</li>
</ul>
<div class="tab-content">
<div class="tab-pane" id="causas">
<div class="span6 offset1">
<%= f.simple_fields_for :levelonecause do |levelone| %>
<%= levelone.input :content, label: 'Causa', as: :text, required: false %>
<%= levelone.link_to_remove "Quitar", :class => 'btn btn-danger' %>
<% end %>
<%= f.link_to_add "Agregar Causa del nivel 1", :levelonecause %>
</div>
</div>
<div class="tab-pane" id="efectos">
<div class="span6 offset1">
<%= f.simple_fields_for :leveltwocause do |leveltwocause| %>
<%= leveltwocause.input :content, label: 'Efect', as: :text, required: false %>
<%= leveltwocause.link_to_remove "Quitar", :class => 'btn btn-danger' %>
<%= leveltwocause.label :levelonecause_id, "Efecto" %>
<%= leveltwocause.collection_select(:levelonecause_id, Levelonecause.all, :id, :content) %>
<% end %>
<%= f.link_to_add "Agregar Efecto del nivel 1", :leveltwocause %>
</div>
</div>
</div>
</div>
</div>
<%= f.button :submit, 'Guardar Datos', class: 'btn btn-primary pull-right' %>
<% end %>
</div>
EDIT
OK guys i removed the trough in my model and it works! does anyone knows why?
This new Rails version is killing me
Try to add :levelonecause_id to attr_accessible list of levelonecause model and the other models that has it too.
I met very strange problem. I have Timetable model and try to write my custom validation. So, now i'm just trying to add test error for field to make sure that everything is ok. But it doesn't work. So, i try to update object of Timetable model but when i don't use my test custom validation everything works perfect. Otherwise i get such error:
NoMethodError in Timetables#update
undefined method `map' for nil:NilClass
32:
33: <div class="controls">
34: <%= f.select( :curriculum_id,
35: options_for_select( #subjects_with_curriculums,
36: #tt.curriculum_id ),
37: { :include_blank => true }) %>
38: </div>
Here is my model:
# == Schema Information
#
# Table name: timetables
#
# id :integer not null, primary key
# curriculum_id :integer
# school_class_id :integer
# tt_day_of_week :string(255)
# tt_number_of_lesson :integer
# tt_room :string(255)
# tt_type :string(255)
# created_at :datetime not null
# updated_at :datetime not null
#
class Timetable < ActiveRecord::Base
belongs_to :curriculum
belongs_to :school_class
has_many :lessons
validates :school_class_id, :presence => { :message => "should exist" }
validates :tt_day_of_week,
:presence => true,
:inclusion => { :in => %w(Mon Tue Wed Thu Fri) }
validates :tt_number_of_lesson,
:presence => true,
:inclusion => {
:in => 1..9,
:message => "should have 1..9 symbols"
}
validates :tt_room,
:length => {
:maximum => 3,
:message => "should have 3 symbols"
},
:allow_blank => true
validates :tt_type,
:inclusion => { :in => ["Primary lesson", "Extra"] },
:allow_blank => true
validate :test
def test
errors.add(:tt_number_of_lesson, "test")
end
end
My controller:
# encoding: UTF-8
class TimetablesController < ApplicationController
...
def edit
#types_of_lesson = collect_types_of_lesson
#tt = Timetable.find( params[:id] )
#subjects_with_curriculums = collect_subjects_with_curriculums( #tt.school_class )
end
def update
#tt = Timetable.find( params[:id] )
if #tt.update_attributes( params[:timetable] )
flash[:success] = "Расписание успешно обновлено!"
redirect_to timetables_path
else
flash.now[:error] = #tt.errors.full_messages.to_sentence :last_word_connector => ", ",
:two_words_connector => ", "
render 'edit'
end
end
private
# Collecting subjects names for school class and curriculum_id for each subject.
def collect_subjects_with_curriculums( school_class )
subjects = school_class.curriculums.collect do |c|
[ c.qualification.subject.subject_name, c.id ]
end
end
def timetable_for_class_with_existance_data( school_class )
return [] if Timetable.all.empty?
Timetable.select do |t|
( t.school_class.class_code == school_class.class_code ) and
not ( t.tt_room.blank? ) and not ( t.tt_type.blank? ) and
not ( t.curriculum_id.nil? )
end.to_a
end
# Return for school class it's timetable.
def timetable_for_class( school_class )
Timetable.select{|t| t.school_class.class_code == school_class.class_code }.to_a
end
def subjects_of_class( school_class )
subjects = school_class.curriculums.collect do |c|
c.qualification.subject.subject_name
end
end
# Return sorted by number of lesson tometable for one day.
def sorted_timetable_for_day( timetable, day )
timetable.select{ |t| t.tt_day_of_week == day }
.sort_by{ |e| e[:tt_number_of_lesson] }
end
# Return russian name for type of lesson.
def collect_types_of_lesson
[ ["Обязательно занятие", "Primary lesson"], ["Электив", "Extra"] ]
end
# Check if timetable already has been created for school class.
def timetable_exists?( school_class )
not timetable_for_class( school_class ).empty?
end
end
My view
<%= form_for #tt, :html => {:class => "form-horizontal"} do |f| %>
<%= field_set_tag do %>
<%= f.hidden_field :tt_number_of_lesson %>
<%= f.hidden_field :tt_day_of_week %>
<%= f.hidden_field :school_class_id %>
<div class="control-group">
<%= f.label :tt_day_of_week, "Day of the week", :class => "control-label" %>
<div class="controls">
<%= content_tag( :span, translate_day_of_week( #tt.tt_day_of_week ),
:class =>"input-xlarge uneditable-input span2" ) %>
</div>
</div>
<div class="control-group">
<%= f.label :tt_number_of_lesson, "Number of lesson", :class => "control-label" %>
<div class="controls">
<%= content_tag( :span, #tt.tt_number_of_lesson,
:class =>"input-xlarge uneditable-input span1" ) %>
</div>
</div>
<hr/>
<div class="control-group">
<%= f.label :curriculum_id, "Type of subject", :class => "control-label" %>
<div class="controls">
<%= f.select( :curriculum_id,
options_for_select( #subjects_with_curriculums,
#tt.curriculum_id ),
{ :include_blank => true }) %>
</div>
</div>
<div class="control-group">
<%= f.label :tt_room, "Code of the room", :class => "control-label" %>
<div class="controls">
<%= f.text_field :tt_room, :class => "span2", :maxlength => 3 %>
</div>
</div>
<div class="control-group">
<%= f.label :tt_type, "Type of the lesson", :class => "control-label" %>
<div class="controls">
<%= f.select( :tt_type,
options_for_select( #types_of_lesson,
#tt.tt_type ),
{ :include_blank => true }) %>
</div>
</div>
<%= f.submit "Update", :class => "btn btn-large btn-warning" %>
<% end %>
<% end %>
When i remove:
<div class="control-group">
<%= f.label :curriculum_id, "Type of subject", :class => "control-label" %>
<div class="controls">
<%= f.select( :curriculum_id,
options_for_select( #subjects_with_curriculums,
#tt.curriculum_id ),
{ :include_blank => true }) %>
</div>
</div>
<div class="control-group">
<%= f.label :tt_type, "Type of the lesson", :class => "control-label" %>
<div class="controls">
<%= f.select( :tt_type,
options_for_select( #types_of_lesson,
#tt.tt_type ),
{ :include_blank => true }) %>
</div>
</div>
I can view my test error. I can't figure what is going on.
You say this in your update controller:
render 'edit'
That simply tells Rails to render the edit template, it doesn't run any of the code associated with the edit controller, it simply renders edit.html.erb in the current context.
From the Layouts and Rendering in Rails Guide:
2.2.2 Rendering an Action’s View
[some stuff about render 'x', render :x, and render :action => :x being the same...]
Using render with :action is a frequent source of confusion for Rails newcomers. The specified action is used to determine which view to render, but Rails does not run any of the code for that action in the controller. Any instance variables that you require in the view must be set up in the current action before calling render.
Pay particular attention to the last sentence:
Any instance variables that you require in the view must be set up in the current action before calling render.
You're setting #subjects_with_curriculums in the edit controller but using the edit view from the update controller. The result is that #subjects_with_curriculums is nil when edit.html.erb tries to use it when update tries to render the edit view.
You'll need to set #subjects_with_curriculums in your update controller, you might need #types_of_lesson as well.