Rails ActiveRecord: Uniqueness validation on a nested model - ruby-on-rails

I have tried the solutions found in the search results but validation is still not working.
Here's the model setup:
class Transaction < ActiveRecord::Base
has_many :trans_items, class_name: "TransItem", dependent: :destroy, inverse_of: :transact
accepts_nested_attributes_for :trans_items
class TransItem < ActiveRecord::Base
belongs_to :transact, class_name: "Transaction", foreign_key: :transaction_id, inverse_of: :trans_items
validates_uniqueness_of :material_id, :scope => :transaction_id
end
This still becomes created successfully:
Transaction
> trans_items
- material_id: 9
- transaction_id: 1
> trans_items
- material_id: 9
- transaction_id: 1
UPDATE 1:
As suggested below, I also tried this solution but still not working:
validates :material_id, uniqueness: { scope: :transaction_id }
If it would help, the create form is this (using nested_form gem):
<%= f.link_to_add "Add Material", :trans_items, :data => { :target => "#trans_items" } %>
<table id="trans_items" class="table table-condensed" cellspacing="0">
<%= f.fields_for :trans_items, wrapper: false do |builder| %>
<tr class="fields">
<td width="10%">
<%= builder.label :qty %><br>
<%= builder.number_field :qty, :class => 'form-control input-sm', :step => 'any' %>
</td>
<td>
<%= builder.label :material_id %>
<%= builder.collection_select(:material_id, Material.all, :id, :material_display_dropdown, {prompt: "Select one..."}, { :class => "form-control input-sm" }) %>
</td>
<td>
<%= f.link_to_remove "Remove" %>
</td>
</tr>
<% end %>
</table>

Try this one:
validates :material_id, uniqueness: { scope: :transaction_id }

Related

Ruby on Rails - undefined method 'ofertum_path'

I have this model Oferta
class Oferta < ActiveRecord::Base
belongs_to :entidade
has_many :candidatos, :through => :interesses
has_many :interesses, foreign_key: "oferta_id", dependent: :destroy
validates :entidade_id, presence: true
validates :titulo, :presence => { :message => "Título tem de ser preenchido" }, length: { maximum: 40, message: "Título muito extenso! Máximo 40 caracteres!" }
validates :corpo, :presence => { :message => "Corpo tem de ser preenchido" }, length: { maximum: 150, message: "Corpo muito extenso! Máximo 150 caracteres!" }
validates :tipo, inclusion: { in: %w(full_time part_time), message: "%{value} não é válido" }
validates :salario, numericality: { only_integer: true }
i have resources :ofertas in the routes file.
And so far the routing is fine and it works. But in my view:
<% provide(:title,"Editar Oferta") %>
<h1>Editar Oferta</h1>
<div class="row">
<div class="span6 offset3">
<%= simple_form_for #oferta do |f| %>
<%= render 'shared/error_messages' %>
<%= f.input :titulo %>
<%= f.input :corpo %>
<%= f.input :data_inicio %>/<%= f.input :data_fim %>
<%= f.input :atividade %>
<%= f.select :tipo, ["full_time","part_time"], :label => "Tipo" %>
<%= f.input :salario %>
<%= f.select :ativa, ["true","false"], :label => "Atiar/Desativar" %>
<% end %>
</div>
</div>
I get a undefined method 'ofertum_path' in the simple_form_for tag.....
my controller so far is this:
class OfertasController < ApplicationController
def edit
#oferta = Oferta.find(params[:id])
end
I just dont get where the ofertum is coming from. Can someone help me?

Nested object not saved on create

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

eliminate instance variable in partial, getting nil

I have a partial that has an instance variable in it. I am trying to eliminate this instance variable because instance variables are not suppose to be in partials. When I try eliminating it I am getting errors
partial with instance variable
<%= f.label :file, "<span style='background-color: ##{#idea.first_color_hex}' >#
{image_tag(f.object.file.url(:icon))}</span>".html_safe %>
partial without instance variable
<%= f.label :file, "<span style='background-color: ##{idea.first_color_hex}' >#
{image_tag(f.object.file.url(:icon))}</span>".html_safe %>
getting nil for idea
what I tried:
creating this variable as an object
<%= f.label :file, "<span style='background-color: ##{f.object.idea.first_color_hex}' >#
{image_tag(f.object.file.url(:icon))}</span>".html_safe %>
getting nil for first_color_hex
Also tried creating an if then statement
<% if f.object.idea.nil? %>
<%= f.label :file, "<span style='background-color: ##{#idea.first_color_hex}' >#
{image_tag(f.object.file.url(:icon))}</span>".html_safe %>
<%else%>
<%= f.label :file, "<span style='background-color: ##{f.object.idea.first_color_hex}'
>#{image_tag(f.object.file.url(:icon))}</span>".html_safe %>
<%end%>
but there is still an instance variable there. Not sure what the if should be
ideas model:
class Idea < ActiveRecord::Base
attr_accessor :product_line_tokens
has_many :artworks, -> { order('dimensions ASC') }
has_and_belongs_to_many :colors, -> { order('name asc').uniq }
has_and_belongs_to_many :imprintables, -> { uniq }, :join_table => :imprintables_ideas
has_and_belongs_to_many :stores, -> { order('name asc').uniq }, :join_table =>
:stores_ideas
has_and_belongs_to_many :taxonomies, -> { order('name asc').order('store_id').uniq },
:join_table => :taxonomies_ideas
has_and_belongs_to_many :product_lines, :join_table => "product_lines_ideas"
belongs_to :default_artwork, :class_name => "Artwork", :foreign_key =>
:default_artwork_id
belongs_to :copywriter, :class_name => 'User', :foreign_key => :copywriter_id
belongs_to :artist, :class_name => 'User', :foreign_key => :artist_id
has_many :mockups
def first_color_hex
if colors.count == 0
return nil
else
return colors[0].hex_code
end
end
partial tag:
<%= render :partial => 'art_show', :locals => {:idea => #idea} %>
I figured it out.
I eliminated the instance variable with if else
<% if f.object.idea.nil? %>
<%= f.label :file, "<span style='background-color: none' >#
{image_tag(f.object.file.url(:icon))}</span>".html_safe %><br />
<%else%>
<%= f.label :file, "<span style='background-color: ##
{f.object.idea.first_color_hex}' >#{image_tag(f.object.file.url(:icon))}</span>".html_safe
%><br />
<%end%>

Ruby: create a parent only if at least 1 child exists

I have a parent - child relationship between Repairs & RepairItems.
A repair must have a least 1 RepairItem to be saved. I've made a nested (simple) form to create a Repair and display 3 blank repair_items.
I'm trying to work out how to make sure that a a Repair has at least 1 repair_item entered to allow the user to save the Repair. Otherwise I need to prompt the user that the repair can't be saved until at least 1 repair_item is entered..
Can anyone point me in the right direction for validation so that a user can't save a Repair without any Repair items entered? Thanks
class Repair < ActiveRecord::Base
attr_accessible :repair_id, :repairer_id, :fault_num, :vehicle_id, :date_reported, :date_closed, :hours_open, :mileage_open, :reported_to, :reported_by,
:repair_items_attributes
belongs_to :vehicle
belongs_to :repairer
has_many :repair_items, :dependent => :destroy
validates_presence_of :vehicle_id
validates_associated :repair_items
accepts_nested_attributes_for :repair_items, :reject_if => lambda { |a| a[:repair_type_id].blank? }, :allow_destroy => true
end
class RepairItem < ActiveRecord::Base
attr_accessible :repair_id, :problem, :solution, :repair_type_id, :priority, :repairer_id, :invoice, :cost, :tax,
:item_state_id, :mileage_closed, :hours_closed, :date_closed
belongs_to :repair
belongs_to :repairer
belongs_to :repair_type
belongs_to :item_state
#validates_presence_of :repair_id
validates_presence_of :repair_type_id
scope :open, where(:item_state_id => 1)
scope :monitor, where(:item_state_id=> 2)
scope :deferred, where(:item_state_id => 3)
scope :closed, where(:item_state_id => 4)
scope :cancelled, where(:item_state_id => 5)
end
class RepairsController < ApplicationController
before_filter :authorise
layout :resolve_layout
def index
#status = 1
#repairItems = RepairItem.open
end
def monitor
#status = 2
#repairItems = RepairItem.monitor
end
def deferred
#status = 3
#repairItems = RepairItem.deferred
end
def closed
#status = 4
#repairItems = RepairItem.closed
end
def cancelled
#status = 5
#repairItems = RepairItem.cancelled
end
def new
#repair = Repair.new
3.times { #repair.repair_items.build }
end
def create
# Instantiate a new object using form parameters
#repair = Repair.new(params[:repair])
# Save the object
if #repair.save
# If the save suceeds, redirect to the list action
redirect_to(repairs_path, :notice => 'Repair Created.')
else
# If the save fails, redisplay the form so user can fix problems
render :action => :new
end
end
<%= simple_form_for( #repair, :defaults => { :disabled => #current_user.read_only, :input_html => { :class => "span10" } }) do |f| %>
<fieldset>
<!-- This will display some text in red at the top of the form telling the user -->
<%= f.error_notification %>
<div class="st-row-fluid">
<div class="span2">
<%= f.association :vehicle, label_method: :fleet_num, value_method: :id, include_blank: true, label: 'Vehicle'%>
<p>Current Kms</p>
<p>Current Hours</p>
<p class="muted">Warranty Expires</p>
<p class="muted">Contract Maintenance</p>
</div>
<div class="span2">
<%= f.input :date_reported, :as => :date_picker, :input_html => { :class => "span10 st-datepicker"} %>
<%= f.input :mileage_open, :label => "Km/Miles" %>
<%= f.input :hours_open %>
</div>
<div class="span2">
<%= f.input :fault_num %>
<%= f.input :reported_to %>
<%= f.input :reported_by %>
</div>
</div>
<div class="row-fluid">
<h4> Items</h4>
<%= f.simple_fields_for :repair_items do |p| %>
<table class="table table-condensed">
<tr>
<%= render "repair_items", :p => p %>
</tr>
</table>
<% end %>
</div>
<%= f.error :base %>
<div class="st-form-actions">
<% if #current_user.read_only == false %>
<%= f.submit nil, :class => 'btn btn-success pull-right' %>
<% end %>
<%= link_to 'Cancel', repairs_path, :class => 'btn btn-danger pull-right' %>
</div>
</fieldset>
<% end %>
partial
<td><%= p.association :repair_type, label_method: :repair_type_label, value_method: :id, include_blank: true, label: 'Repair Type'%></td>
<td><%= p.input :problem %></td>
<td><%= p.input :solution %></td>
<td><%= p.input :priority %></td>
<td><%= p.association :repairer, label_method: :rep_name, value_method: :id, include_blank: true, label: 'Repairer'%></td>
</tr>
<tr>
<td><%= p.input :invoice %></td>
<td><%= p.input :cost %></td>
<td><%= p.input :tax %></td>
<td><%= p.input :date_closed, :as => :date_picker, :input_html => { :class => "span10 st-datepicker"} %></td>
<td><%= p.input :mileage_closed, :label => "Km/Miles" %></td>
<td><%= p.input :hours_closed %></td>
<td><%= p.association :item_state, label_method: :state_label, value_method: :id, label: 'Status', :default => 1 %></td>
Use validates_associated :repair_items in the repair to validate the repair items. The action has to construct the repair items using repair.RepairItem.build, so that the items will be associated with the repair, before attempting to save the repair. The repair is constructed before the repair items, but the repair_items will block the associated repair from saving.

Multiple Level Nested Form Can't mass-assign protected attributes:

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.

Resources