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%>
Related
I am using Ruby 2.6.5 and Rails 5.2.3. I have a form with double nested objects with Cocoon. The form is for Preorders. A Preorder can have many Dancers. Dancers can have many and belong to many Groups, so I set up a join table called DancerGroup.
I use Cocoon to add dancers_attributes to the Preorder form, and again to add dancer_groups_attributes inside of the dancers_attributes fields.
My problem is that when I attempt to save a Preorder with a new Dancer and new DancerGroup associations I get the following error:
Dancers dancer groups dancer can't be blank
Which clearly means it's trying to save the dancer_group object before the dancer record has an id The obvious answer is that since I'm using Rails 5, the belongs_to association is required by default, and the work around is to properly use inverse_of and accepts_nested_attributes_for methods to let Rails manage saving everything all at once. But it's not working when it comes to my join table. I even get the same error when I set optional: true on the belongs_to :dancer in the DancerGroup model.
My strong params look like this:
private
def preorder_params
params.require(:preorder).permit( :event_id,
:dancers_attributes => [
:_destroy,
:id,
:name,
:dancer_groups_attributes => [
:_destroy,
:group_id,
:id ]
]
)
end
My models look like this:
app/models/preorder.rb
class Preorder < ApplicationRecord
belongs_to :event
has_many :dancers, dependent: :destroy, inverse_of: :preorder
has_many :dancer_groups, through: :dancers, dependent: :destroy
with_options reject_if: :all_blank, allow_destroy: true do
accepts_nested_attributes_for :dancers
accepts_nested_attributes_for :dancer_groups
end
validates :dancers, :length => { minimum: 1 }
...
end
app/models/dancer.rb
class Dancer < ApplicationRecord
belongs_to :preorder, counter_cache: true, inverse_of: :dancers
has_many :dancer_groups, inverse_of: :dancer, dependent: :destroy
has_many :groups, through: dancer_groups
with_options reject_if: :all_blank, allow_destroy: true do
accepts_nested_attributes_for :dancer_groups
end
...
end
app/models/dancer_group.rb
class DancerGroup < ApplicationRecord
belongs_to :dancer, inverse_of :dancer_groups
belongs_to :group, inverse_of :dancer_groups
...
end
And here's what my form files look like
views/admin/preorders/_form.html.haml
...
%fieldset
%legend Dancers
#dancers
- #preorder.dancers.each do |dancer|
= f.fields_for :dancers, dancer do |ff|
= render "dancer_fields", f: ff, preorder: #preorder
= link_to_add_association f, :dancers,
{ "data-association-insertion-node": "#dancers",
"data-association-insertion-method": "append",
render_options: { locals: { preorder: #preorder } },
class: "btn btn-info btn-sm btn-simple float-right" } do
= icon "fas", "plus"
Add Dancer
...
views/admin/preorders/_dancer_fields.html.haml
...
.card.preorder_dancer
.card-header.row
.col
%h4.card-title Dancer Info
.col-auto
= link_to_remove_association f, { wrapper_class: "preorder_dancer",
class: "btn btn-sm btn-icon btn-simple btn-danger" } do
= icon "fas", "times"
.card-body
.row.pb-3
.col
= f.label :name do
Full Name
%span.text-danger *
= f.text-field :name, class: "form-control"
%h4.card-title Dance Groups
.row{ :id => "dancer_groups_#{f.object.id}" }
- f.object.dancer_groups.each do |dancer_group|
= f.fields_for :dancer_groups, dancer_group do |ff|
= render "dancer_group_fields, f: ff,
preorder: preorder
=link_to_add_association f, :dancer_groups,
{ "data-association-insertion-node": "#dancer_groups_#{f.object.id}",
"data-association-insertion-method": "append",
render_options: {locals: { preorder: preorder } },
class: "btn btn-info btn-sm btn-simple float-right" } do
=icon "fas", "plus"
Add Dance Group
views/admin/preorders/_dancer_group_fields.html.haml
.col-lg-6.preorder_dancer_group
.card.bg-dark
.card-header.row
.col
%h4.card-title Dance Group
.col.text-right
=link_to_remove_association f, { wrapper_class: "preorder_dancer_group",
class: "btn btn-sm btn-icon btn-simple btn-danger"} do
=icon "fas", "times"
.card-body
.row
.col
=f.label :group_id do
Group
%span.text-danger *
=f.collection_select :group_id,
preorder.event.groups,
:id,
:name,
{include_blank: "Select Group"},
{class: "form-control"}
In your _dancer_fields partial you write
%h4.card-title Dance Groups
.row{ :id => "dancer_groups_#{f.object.id}" }
- f.object.dancer_groups.each do |dancer_group|
= f.fields_for :dancer_groups, dancer_group do |ff|
= render "dancer_group_fields, f: ff,
preorder: preorder
and that should be
%h4.card-title Dance Groups
.row{ :id => "dancer_groups_#{f.object.id}" }
= f.fields_for :dancer_groups do |ff|
= render "dancer_group_fields, f: ff,
preorder: preorder
Because otherwise you are not making the dancer-group "connected" to the dancer.
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 }
In my Ruby on Rails application I am trying to display a three drop down menus in the _form.html.erb which are rendered from the file _booking_lookup.html.erb and get there data from the drop down menu methods in the models.
_form.html.erb:
<%= render(:partial => '/booking_lookup', :locals=> {:film => #film = Film.all, :showings => #showings = Showing.all, :seats => #seats = Seat.all, :my_path => '/films/booking_lookup' }) %>
_booking_lookup.html.erb:
<%= form_tag my_path, :method=>'post', :multipart => true do %>
<%= select_tag ('title_id'),
options_from_collection_for_select(#films, :id, :title_info, 0 ),
:prompt => "Film" %>
<%= select_tag ('showings_id'),
options_from_collection_for_select(#showings, :id, :showing_times, 0 ),
:prompt => "Showings" %>
<%= select_tag ('seat_id'),
options_from_collection_for_select(#seats, :id, :seats_available, 0 ),
:prompt => "Seats" %>
<%= submit_tag 'Search' %>
film.rb:
class Film < ActiveRecord::Base
has_many :showings
belongs_to :certificate
belongs_to :category
def title_info
"#{title}"
end
end
seat.rb:
class Seat < ActiveRecord::Base
belongs_to :screen
has_many :bookings
def seats_available
"#{row_letter}#{row_number}"
end
end
showing.rb:
class Showing < ActiveRecord::Base
belongs_to :film
has_many :bookings
belongs_to :screen
def showing_times
"#{show_date.strftime("%e %b %Y")} # #{show_time.strftime("%H:%M")}"
end
end
But for some reason with the line: <%= select_tag ('title_id'),
options_from_collection_for_select(#films, :id, :title_info, 0 ),
:prompt => "Film" %> I get the error:
NoMethodError in Bookings#new
undefined method `map' for nil:NilClass
The weird part is that I am using a lot of this code else where, I have a _multi_search.html.erb form:
<%= form_tag my_path, :method=>'post', :multipart => true do %>
<!-- Genre: -->
Search By:
<%= select_tag ('cat_id'),
options_from_collection_for_select(#categories, :id, :category_info, 0 ),
:prompt => "Genre" %>
<%= select_tag ('cert_id'),
options_from_collection_for_select(#certificates, :id, :certificate_info, 0 ),
:prompt => "Age Rating" %>
<%= text_field_tag :search_string, nil, placeholder: "ACTOR" %>
or
<%= select_tag ('title_id'),
options_from_collection_for_select(#films, :id, :title_info, 0 ),
:prompt => "Film" %>
<%= submit_tag 'Search' %>
<% end %>
And is used in the application.html.erb:
<%= render(:partial => '/multi_search', :locals=> {:categories => #categories = existing_genres, :certificates => #certificates = Certificate.all, :films => #films = Film.all, :my_path => '/films/multi_find' }) %>
And that works fine.
What am I doing wrong?
It looks like #films is nil. Try setting #films = Film.all (instead of #film = Film.all) in _form.html.erb.
Update:
I would recommend moving the queries to the controller action. In the Model-View-Controller pattern, Controllers should be asking Models for data, not Views.
# BookingLookupController
def new
#films = Film.all
#showings = Showing.all
#seats = Seat.all
end
You can then reference the instance variables in the view.
<%= render partial: '/booking_lookup', locals: {films: #films, showings: #showings, seats: #seats, my_path: '/films/booking_lookup' } %>
In Controller, select fields as you just want to display names in dropdown
def method_name
#films = Film.select([:id, :title_info])
#showings = Showing.select([:id, :showing_times])
#seats = Seat.select([:id, :seats_available])
end
In page
<%= render(:partial => '/booking_lookup', :locals=> {:films => #films, :showings => #showings, :seats => #seats, :my_path => '/films/booking_lookup' }) %>
In partial
options_from_collection_for_select(films, :id, :title_info, 0 ),:prompt => "Film" %>
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.