i have somes relations in my table like this
Model : Floors
has_many :photo
Model : Photo
belongs_to :floors
belongs_to :file_type
Model : file_type
has_many :photo
Photo are nested attributes with render inside floors form.
The problem is if i change the file type inside the form without any other change in the form, the new selected alements are not updated, and the update_attributes (in the WEBrick) console, the new selected are not updated.
Photo are a paperclip element with versioning. I don't want to update each time the file if i just want to change his file type related.
Thanks for your help.
EDIT : Has asked, my views.
# _form.html.erb
<% f.fields_for :floor_photo do |floor_photo| -%>
<%= render 'floor_photo_fields', :f => floor_photo %>
<% end -%>
<div>
<%= link_to_add_fields "Add Photo", f, :floor_photo %>
</div>
# _floor_photo_fields.html.erb
<div class="fields">
<%= f.label 'Photo' %><br/>
<%= f.file_field :photo %>
<%= f.collection_select :file_type_id, FileType.all(:order => 'name'), :id, :name, {:prompt => 'Select'}%>
<%= link_to_remove_fields "remove", f %><br/>
<div style="margin-bottom:10px;"><%= f.object.photo_file_name %></div>
</div>
For now, if i click Add Photo, and set a file type to the photo, it's work, but when i edit a floors and want to change the file type, he don't want to take the new file_type_id and don't do any update sql statement. Like if i have nothing changed in my form.
And yes, sorry for my relations, it was a typo mistake, all are good in my models form.
# floor_photo.rb
class FloorPhoto < ActiveRecord::Base
versioned
belongs_to :floor
belongs_to :file_type
has_attached_file :photo, :keep_old_files => true, :url => "/system/buildings/photos/:id/:version/:basename.:extension",
:path => ":rails_root/public/system/buildings/photos/:id/:version/:basename.:extension"
Paperclip.interpolates :version do |attachment, style|
attachment.instance.version.to_s
end
end
# file_type.rb
class FileType < ActiveRecord::Base
has_many :floor_photos
end
I hope this help someone to help me.
Sorry, here is my controller
floors_controllers.rb
def edit
#floor = Floor.find(params[:id])
end
def update
#floor = Floor.find(params[:id])
if #floor.update_attributes(params[:floor])
redirect_to space_path(#floor)
else
render :action => 'edit'
end
end
The code doesn't look right:
Model : Floors
has_many :photo #should be :photos
Model : Photo
belongs_to :floors #should be :floor
belongs_to :file_type
Model : file_type
has_many :photo #should be :photos
Related
I am trying to make a player character generator. I have a form that hopefully will allow me to attach skills with their values to a character sheet model. I made models like this:
class CharacterSheet < ApplicationRecord
has_many :character_sheet_skills, dependent: :destroy
has_many :skills, through: :character_sheet_skills
belongs_to :user
accepts_nested_attributes_for :skills
end
class Skill < ApplicationRecord
has_many :character_sheet_skills, dependent: :destroy
has_many :character_sheets, through: :character_sheet_skills
attr_reader :value
end
class CharacterSheetSkill < ApplicationRecord
belongs_to :skill
belongs_to :character_sheet
end
Character sheet model holds data about player character and skill model has all skills available in game. In CharacterSheetSkill I'd like to store the skills that the player chooses for his character together with an integer field setting the skill value.
When opening form, I already have a full list of skills in database. All I want to do in form is create a character sheet that has all of these skills with added value. I tried using "fields_for" in form, but I couldn't really get that to work. Right now it looks like this:
<%= simple_form_for [#user, #sheet] do |f| %>
<%= f.input :name %>
<%= f.input :experience, readonly: true, input_html: {'data-target': 'new-character-sheet.exp', class: 'bg-transparent'} %>
...
<%= f.simple_fields_for :skills do |s| %>
<%= s.input :name %>
<%= s.input :value %>
<% end %>
<% end %>
How can I make that form so it saves character sheet together with CharacterSheetSkills?
A better idea here is to use skills as a normalization table where you store the "master" definition of a skill such as the name and the description.
class CharacterSheetSkill < ApplicationRecord
belongs_to :skill
belongs_to :character_sheet
delegate :name, to: :skill
end
You then use fields_for :character_sheet_skills to create rows on the join table explicitly:
<%= f.fields_for :character_sheet_skills do |cs| %>
<fieldset>
<legend><%= cs.name %></legend>
<div class="field">
<%= cs.label :value %>
<%= cs.number_field :value %>
</div>
<%= cs.hidden_field :skill_id %>
</fieldset>
<% end %>
Instead of a hidden fields you could use a select if you want let the user select the skills.
Of course nothing will show up unless you "seed" the inputs:
class CharacterSheetController < ApplicationController
def new
#character_sheet = CharacterSheet.new do |cs|
# this seeds the association so that the fields appear
Skill.all.each do |skill|
cs.character_sheet_skills.new(skill: skill)
end
end
end
def create
#character_sheet = CharacterSheet.new(character_sheet_params)
if #character_sheet.save
redirect_to #character_sheet
else
render :new
end
end
private
def character_sheet_params
params.require(:character_sheet)
.permit(
:foo, :bar, :baz,
character_sheet_skill_attributes: [:skill_id, :value]
)
end
end
I am using Rails 4.
In my project, include nested form for has_many relationship. From UI point of view, I got it. But nested form values are not inserting into database.
class Newspaper < ActiveRecord::Base
has_to :newspaper_categories, :dependent_destroy => true
accepts_nested_attributes_for :newspaper_categories, :allow_destroy => true, :reject_if => :all_blank
end
class NewspaperCategory < ActiveRecord::Base
belongs_to :newspaper
end
Newspaper form contents like,
<%= nested_form_for(#newspaper) do |f| %>
# Newspaper form fields
# Include `Newspaper category` form from the file.
<%= f.fields_for :newspaper_categories do |nc|%>
<%= render "newspaper_category" %>
<% end %>
# For add new form using JS
<%= f.link_to_add "Add New", :newspaper_categories %>
<%= f.submit %>
<% end %>
In my Newspaper Controller,
# add build in new method,
def new
#newspaper = Newspaper.new
#newspaper.newspaper_categoried.build
end
# In params set task_attributes,
def newspaper_params
params.require(:newspaper).permit(:name, :logo, task_attributes[:cat_link, :_destroy])
end
Where I goes wrong, still i'm confusing to insert
Update this
params.require(:newspaper).permit(:name, :logo, {newspaper_categories_attributes: [ :_destroy, :category_id, :rss_link, :image_url]})
I have such models:
class Grade < ActiveRecord::Base
has_many :question_grades
end
class QuestionGrade < ActiveRecord::Base
belongs_to :grade
belongs_to :question
# it has integer :number
end
class Question < ActiveRecord::Base
# it has string :label
end
I have a simple_form for the 'grade' model, which iterates question_grades:
<%= simple_form_for #grade, :url => "/homeworks/update_grade", :method => :post do |f| %>
<%= f.simple_fields_for :question_grades do |q| %>
<%= q.association :question %>
<%= q.input :number, :collection => 0..2, label: false%>
</div>
</div>
This form creates an editable form for each 'question_grade', where allows visitors to edit 'number' attribute of question_grade. I also want to show a label by using the value, 'question_grade.question.label'. I created an association with 'q.association :question' but it creates an editable input form item. I want to access a value in the association. How can I do that?
When you do
<%= q.association :question %>
you are creating a field to edit this association, as you can see.
What do you need, is to access the q.object, defined as attr_reader here .
in this case, it will be your QuestionGrade instance.
so this:
<%= q.object.question.label %>
may solve your problem.
I am trying to build a simple_nested_form in my Ruby on Rails app. When I submit my form I am getting some unknown error because it is just redirecting back to the form to input again. Here is the output in the rails server console for when I submit the form. It looks like there is some random "0" => thrown in there.
Parameters: {"machine"=>{"name"=>"2134", "ip_adress"=>"2", "machine_employees_attributes"=>{"0"=>{"machine_id"=>"1", "employee_id"=>"2"}}}, "commit"=>"Create Machine"}
I have a machine model which has_many :machine_employees
and a machineemployee model which belongs_to :machine
Do you have any idea why this 0 => could be appearing because I think it is what is giving me the issues.
Here is the code for my models.
Machine
class Machine < ActiveRecord::Base
# Relationships
has_many :machine_employees
has_many :employees, :through => :machine_employees
accepts_nested_attributes_for :machine_employees, :reject_if => lambda{ |me| me[:employee_id].blank? }
attr_accessible :ip_adress, :name, :machine_employees_attributes
# Validations
validates_presence_of :name, :ip_adress
end
MachineEmployee
class MachineEmployee < ActiveRecord::Base
before_validation :set_default
# Relationships
belongs_to :machine
belongs_to :employee
attr_accessible :employee_id, :machine_id, :end_date, :start_date
# Validations
validates_presence_of :employee_id, :machine_id, :start_date
private
# Callback Methods
def set_default
self.start_date = Date.today
self.end_date = nil
end
end
New Machine Form
<div class="row-fluid">
<div class="span3">
<h1>Add a Machine</h1>
<br />
<%= simple_nested_form_for #machine do |f| %>
<%= render "machine_fields", :f => f %>
<%= f.button :submit %>
<%= link_to 'Back', machines_path %>
</div>
<div class="span4">
<h4>Assign an Employee to This Machine</h4>
<%= f.simple_fields_for :machine_employees do |me_form| %>
<!-- render nested machine_employee fields-->
<%= render "machine_employee_fields", :f => me_form %>
<% end %>
</div>
<% end %>
</div>
Machine Employee Fields Partial
<%= f.input :machine_id, :as => :hidden, :input_html => { :value => #machine.id } %>
<%= f.input :employee_id, collection: #employees, :id => :name, :prompt => "Select ..." %>
The 0 is thrown in there because the machine model has_many machine_employees. When you use nested forms, it passes a pseudo-array for has_many relations. So, if you tried to submit 2 machine employees, your hash would look like this:
Parameters: {"machine"=>{"name"=>"2134", "ip_adress"=>"2", "machine_employees_attributes"=>{
"0"=>{"machine_id"=>"1", "employee_id"=>"2"},
"1"=>{"machine_id"=>"1", "employee_id"=>"3"}
}
}, "commit"=>"Create Machine"}
This way you can access the machine_employees passed from the form by doing params[:machine][:machine_employees_attributes][0] or params[:machine][:machine_employees_attributes][1]. Note that if this was a has_one relationship, then the machine_employees_attributes key would be changed to machine_employee_attributes and there would be no numerical index.
I suspect the problem is that your machine model must accept_nested_attributes_for :machine_employees and must also have attr_accessible :machine_employees_attributes.
I have a Carrierwave image upload in a nested simple_form which works (sort of) unless the user does not specify a file, in which case a blank Picture object is created unless there was a previously existing one. Not quite sure how to make it so that if the user doesn't specify a "new" image to upload, the old one isn't deleted and/or a blank record without a file is created.
One (maybe odd) thing I am doing is always sending the logged in #user to the user#edit action, then building a #user.picture if it doesn't exist. I am thinking this is where my bad design is.
# user.rb
class User < ActiveRecord::Base
[...]
has_one :picture, :dependent => :destroy
accepts_nested_attributes_for :picture
[...]
end
# picture.rb
class Picture < ActiveRecord::Base
attr_accessible :image, :remove_image
belongs_to :user
mount_uploader :image, ImageUploader
end
# users_controller.rb
def edit
if #user.picture.nil?
#user.build_picture
end
end
#_form.html.erb
<%= simple_form_for #user, :html => {:multipart => true} do |f| %>
<%= render "shared/error_messages", :target => #user %>
<h2>Picture</h2>
<%= f.simple_fields_for :picture do |pic| %>
<% if #user.picture.image? %>
<%= image_tag #user.picture.image_url(:thumb).to_s %>
<%= pic.input :remove_image, :label => "Remove", :as => :boolean %>
<% end %>
<%= pic.input :image, :as => :file, :label => "Picture" %>
<%= pic.input :image_cache, :as => :hidden %>
<% end %>
<br/>
#rest of form here
<% end %>
I think I had the same issue which I solved by adding a reject_if option to the accepts_nested_attribute. So in your example, you could do something like
class User < ActiveRecord::Base
[...]
has_one :picture, :dependent => :destroy
accepts_nested_attributes_for :picture,
:reject_if => lambda { |p| p.image.blank? }
[...]
end
When you use build_* it sets the foreign key on the object. ( similar to saying Picture.new(:user_id => id) )
Try This
# users_controller.rb
def edit
if #user.picture.nil?
#user.picture = Picture.new
end
end
Today I had the same problem, I solved this like:
accepts_nested_attributes_for :photos,
:reject_if => :all_blank