rails nested attributes not save to images table - ruby-on-rails

i'm trying to save two object (image and event) using one form (event form),
but the when i submit the button there is only event object that created, the images object not save to images table,
models/event.rb
has_one :images, :class_name => '::Refinery::Image'
accepts_nested_attributes_for :images, :allow_destroy => true
models/image.rb
belongs_to :events, class_name: 'Refinery::Events::Event'
events_controller.rb
def new
#event = Event.new
#event.build_images
end
def create
#event = Event.new(event_params)
end
def event_params
params.require(:event).permit(:nama, :deskripsi, images_attributes:[:id, :image_name, :image_size, :image_width, :image_height, :created_at, :updated_at, :image_mime_type, :image_uid, :image_title, :image_alt, :event_id] )
end
events/_form.html.erb
<%= form_for [refinery, :events, #event], :html => { :multipart => true } do |f| %>
<%= render '/refinery/admin/error_messages',
:object => #event,
:include_object_name => true %>
<div class='field nama_field string_field'>
<%= f.label :nama %>
<%= f.text_field :nama %>
</div>
<div class='field deskripsi_field text_field'>
<%= f.label :deskripsi %>
<%= f.text_area :deskripsi, :rows => 8 %>
</div>
<%= f.fields_for :images do |ff| %>
<div>
<%= ff.label :images %>
<%= ff.file_field :images %>
</div>
<% end %>
<div class='actions'>
<%= f.submit t('.send') %>
</div>
<% end %>
anyone can help me why the images not saved into images table?

Related

How do I save a form in double nested form?

I have three models: Event, Workout, and Round.
A person can create a event, that includes a workout, and configure number of sets and weights through round.
I am currently using cocoon gem to create a nested form. I am able to use the form and save Event and Workout, however, Round is not being saved.
class Event < ActiveRecord::Base
has_many :workouts, dependent: :destroy
has_many :rounds, :through => :workouts
belongs_to :user
accepts_nested_attributes_for :workouts, :allow_destroy => true
end
class Workout < ActiveRecord::Base
belongs_to :event
has_many :rounds, dependent: :destroy
accepts_nested_attributes_for :rounds, :allow_destroy => true
end
class Round < ActiveRecord::Base
belongs_to :workout
belongs_to :event
end
I currently have my routes set like this.
Rails.application.routes.draw do
devise_for :users
root 'static_pages#index'
resources :events do
resources :workouts do
resources :rounds
end
end
In my controller, this is how I have my new methods.
New Method for Event
def new
#event = current_user.events.new
end
New Method for Workout
def new
#workout = Workout.new
end
New Method for Round
def new
#round = Round.new
end
I currently have the form under Events' view folder. Under show.html.erb of Events view file, I am trying to display Rounds as well by
<% #workout.rounds.each do |round| %>
<%= round.weight %>
<% end %>
But I am getting undefined method for rounds. Is it not possible to display round in Event view?
Thanks for the help!
Edit 1:
Here is my nested forms.
At the top, I have form for Event.
<%= simple_form_for #event do |f| %>
<%= f.input :title %>
<h3>Work Outs</h3>
<div id="workouts">
<%= f.simple_fields_for :workouts do |workout| %>
<%= render 'workout_fields', f: workout %>
<% end %>
<div class="links">
<%= link_to_add_association 'add workout', f, :workouts %>
</div>
</div>
<div class="field">
<%= f.label :start_time %><br>
<%= f.datetime_select :start_time %>
</div>
<div class="field">
<%= f.label :end_time %><br>
<%= f.datetime_select :end_time %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="actions">
<%= f.submit "Create new Workout" %>
</div>
<% end %>
<% end %>
</form>
Then there is a form for Workout
<div class="nested-fields">
<%= f.input :name %>
<div class="rounds">
<%= f.simple_fields_for :rounds, :wrapper => 'inline' do |round| %>
<%= render 'round_fields', f: round %>
<% end %>
<div class="links">
<%= link_to_add_association 'add round', f, :rounds, :render_option => { :wrapper => 'inline' } %>
</div>
</div>
<%= link_to_remove_association "remove workout", f %>
</div>
And finally, I have the form for Round
<div class="nested-fields">
<table class="table round-table">
<tr>
<td>
<% index = 0 %>
<%= f.simple_fields_for :rounds do |round| %>
<%= render 'set_fields', {f: round, index: index} %>
<% index = index + 1 %>
<% end %>
</td>
<td>Previous Weight</td>
<td><%= f.input_field :weight %></td>
<td><%= f.input_field :repetition %></td>
<td><%= link_to_remove_association "remove rounds", f %></td>
</tr>
</table>
</div>
I am able to create round on rails console and save them. But when I use the form on the web, I cannot save them.
EDIT 2
This is currently how I have the event_params and workout_params set-up.
def event_params
params.fetch(:event, {}).permit(:title, :description, :start_time, :end_time, :workouts_attributes => [:id, :name, :category, :_destroy])
end
Then the workout_params:
def workout_params
params.require(:workout).permit(:name, :category, :rounds_attributes => [:id, :weight, :set, :repetition, :_destroy])
end
I am confused why the form would save Event and Workout. But Round always returns an empty array.
Finally solved it!
I had to have an association in the params as well. Double nested association.
def event_params
params.fetch(:event, {}).permit(:title, :description, :start_time, :end_time, :workouts_attributes => [:id, :name, :category, :_destroy])
end
For my event_params, I only had :workouts_attributes. I thought having :rounds_attributes in workout_params would be okay. But I needed to have rounds_attributes in event_params as well.
Fixing it like below fixed the issue.
def event_params
params.fetch(:event, {}).permit(:title, :description, :start_time, :end_time, :workouts_attributes => [:id, :name, :category, :_destroy, :rounds_attributes => [:id, :weight, :set, :repetition, :_destroy]])
end
you already have rounds attribute in Events model (has_many :rounds, :through => :workouts), why not use it?
<% #event.rounds.each do |round|
<%= round.weight %>
<% end %>

Form for has_many :through

Could you please show how form should look for has_many :through association?
user.rb
has_many :participations
has_many :events, :through => :participations
event.rb
has_many :participations
has_many :users, :through => :participations
accepts_nested_attributes_for :participations
participations.rb
belongs_to :user
belongs_to :event
events_controller.rb
def new
#event = Event.new
#participation = #event.participations.build
end
def create
#event = Event.new(params[:event].permit!)
respond_to do |format|
if #event.save
format.html { redirect_to events_path, notice: 'Event was successfully created.' }
else
format.html { render action: 'new' }
end
end
end
But I have some doubts about
_form.html.erb
<%= form_for #event, :html => {:class => 'row'} do |f| %>
<div class="form-group">
<%= f.label :name, :class => 'control-label' %><br>
<%= f.text_field :name, :class => 'form-control' %>
</div>
<div class="form-group">
<%= f.label :description, :class => 'control-label' %><br>
<%= f.text_area :description, :class => 'form-control' %>
</div>
<div class="form-group">
<%= f.fields_for :participations do |f_p| %>
<%= f_p.label :user_ids, "Users" %>
<%= f_p.select :user_ids, options_from_collection_for_select(User.all, :id, :name), { :multiple => true } %>
<% end %>
</div>
<div class="actions">
<%= f.submit 'Save', :class => 'btn btn-default' %>
</div>
<% end %>
What is the best way to add Users for a new Event?
Thanks in advance!
Instead of
<div class="form-group">
<%= f.fields_for :participations do |f_p| %>
<%= f_p.label :user_ids, "Users" %>
<%= f_p.select :user_ids, options_from_collection_for_select(User.all, :id, :name), { :multiple => true } %>
<% end %>
</div>
You could try:
<div class="form-group">
<% User.all.each do |user| %>
<%= check_box_tag 'event[user_ids]', user.id, #event.user_ids.include?(user.id) -%>
<%= label_tag user.name %>
<% end %>
</div>
Just found more elegant solution:
form.html.erb
<div class="form-group">
<%= f.label :user_ids, "Participants" %><br>
<%= f.collection_select :user_ids, User.order(:name), :id, :name, {}, {:multiple => true} %>
</div>
more you can find here: http://railscasts.com/episodes/258-token-fields-revised

Nested attributes (Paperclip) validation

I'm working on a nested form where a user when creating a Screen should also attached an image (a separate model called Screenshot). I'm trying to validate the presence of the attachment before saving the new Screen to the db. I tried to validate the presence of the attachment in the Screenshot model, but that only precent Screenshot to be saved, while it still creates a Screen.
Here's my models:
class Screen < ActiveRecord::Base
belongs_to :project
has_many :screenshots
validates :name, presence: true
accepts_nested_attributes_for :screenshots
validates_presence_of :screenshots
end
class Screenshot < ActiveRecord::Base
belongs_to :screen
has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" }
end
here's my controller:
def create
#screen = Screen.create(screen_params)
if #screen.save
flash[:notice] = "A new screen has been added to this project"
redirect_to [#screen.project]
else
render :action => 'new'
end
end
And lastly here's my form:
<%= form_for ([#project, #screen]), :html => { :multipart => true } do |f| %>
<% if #screen.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#screen.errors.count, "error") %> prohibited this screen from being saved:</h2>
<ul>
<% #screen.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.hidden_field :project_id %>
</div>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_field :description %>
</div>
<%= f.fields_for :screenshots, #screen.screenshots.build do |s| %>
<%= s.hidden_field :screen_id, :value => #screen.id %>
<%= s.hidden_field :version, :value => "1" %>
<%= s.label :image %><br>
<%= s.file_field :image %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Any help to this noob is greatly appreciated.
Several things for you:
Form
You shouldn't build new objects in the form itself. That needs to happen in the controller's new function
<%= f.fields_for :screenshots do |s| %>
<%= s.hidden_field :screen_id, :value => #screen.id %>
<%= s.hidden_field :version, :value => "1" %>
<%= s.label :image %><br>
<%= s.file_field :image %>
<% end %>
You can declare them like this:
def new
#screen = Screen.new
#screen.screenshots.build
#any more build declarations go here
end
Verification
I believe you should put the verification into the screnshots model, as the nested parameters are passed directly to the corresponding model. I'm not sure on that though.
In the screenshots model, I would put the validates_presence_of :screenshots, with the name as your Paperclip attachment's name

Rails - :_destroy method not working

I am trying to use :_destroy method in a nested form, but it just does not work
There are two models:
class Setting < ActiveRecord::Base
attr_accessible :category, :name, :setting_items_attributes, :_destroy
attr_accessor :_destroy
has_many :setting_items, :dependent => :destroy
accepts_nested_attributes_for :setting_items, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
end
class SettingItem < ActiveRecord::Base
attr_accessible :setting_id, :value
belongs_to :setting
end
In the controller I create a instance:
def edit
#setting = Setting.find(params[:id])
#setting.setting_items.build
end
And the form looks like this:
<%= form_for(#setting) do |f| %>
<div class="field">
<%= f.label :category %>
<%= f.text_field :category %>
</div>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<hr>
<h3>Params:</h3>
<%= f.fields_for :setting_items do |s| %>
<span>
<div class="fields">
<%= s.text_field :value %>
<%= s.hidden_field :_destroy %>
<%= link_to_function "delete", "remove_fields(this)"%>
</div>
<% end %>
<div class="actions">
<%= f.submit "Update", :class => "btn btn-primary"%>
</div>
<% end %>
Also the function I use is here:
function remove_fields(link){
$(link).prev("input[type=hidden]").val("1");
$(link).parent().fadeOut("slow");
}
So the setting_items form is simply not working at all, It shows the update is successful, but nothing is actually added or deleted.
for example->your model associations are as follows: just follow the below steps to make use of magical _destroy attribute
####parent model
plan.rb
has_many :members,:dependent => :destroy
#this is important you want to destroy nested records
accepts_nested_attributes_for:members,:allow_destroy => true
attr_accessible :members_attributes
##child model
member.rb
belongs_to :plan
######controller
def edit
#plan.Plan.find(params[:id])
end
#####edit.html.erb
<%= form_for #plan do |f| %>
<%= f.fields_for :members do |member| %>
<div class="member">
<%= member.text_field :title%>
<%= image_tag 'delete.png',:class =>'remove_member',:id=>member.id %>
<!-- we need to set this hidden field value as 1 to mark it to be deleted during save/update of parent-->
<%= member.hidden_field :_destroy, :class => 'delete_member', :member_id => member.id %>
<!--similar to
<input id="plan_members_attributes_0__destroy" class="delete_member" type="hidden" value="false" name="plan[members_attributes][0][_destroy]" member_id="#{id of member}">
-->
</div>
<%end%>
<%end%>
##add js onclick of remove button/image
$('.delete_member').click(function(){
//remove div from screen
$(this).closest('.member').remove();
//get relevant id to remove/mark as delete
id =jQuery(this).attr('id');
//remove/mark the nested model/record as ready for deletion for rails by adding true/1 value
$("input[member_id="+id+"]").attr('value',1);
})

rails field_for associated model tags with error "undefined method `model_name' for Array:Class'"

according to http://guides.rubyonrails.org/getting_started.html, I have below relationship models,
class Tag < ActiveRecord::Base
belongs_to :post
attr_accessible :name
end
class Post < ActiveRecord::Base
attr_accessible :context, :title, :tags_attributes
validates :title, :presence => true
validates :context, :presence => true, :length => {:minimum => 5}
has_many :comments
has_many :tags
accepts_nested_attributes_for :tags, :allow_destroy => :true,
:reject_if => proc {|attrs| attrs.all? {|k,v| v.blank?} }
end
normally below code could work well when I sent a edit request,these existing tags are listed as editable elements on the page.
<%= form_for(#post) do |post_form| %>
<%= post_form.fields_for :tags do |tag_form|%>
<div class="field">
<%= tag_form.label :name, 'Tag:' %>
<%= tag_form.text_field :name %>
</div>
<% unless tag_form.object.nil? || tag_form.object.new_record? %>
<div class="field">
<%= tag_form.label :_destroy, 'Remove:' %>
<%= tag_form.check_box :_destroy %>
</div>
<% end %>
<% end %>
but now,refer to below instance code on http://guides.rubyonrails.org/form_helpers.html
<%= form_for #person, :url => { :action => "create" } do |person_form| %>
<%= person_form.text_field :name %>
<%= fields_for #person.contact_detail do |contact_details_form| %>
<%= contact_details_form.text_field :phone_number %>
<% end %>
<% end %>
then I change the statement with fields_for to below format, why it always always prompt
undefined method `model_name' for Array:Class
<%= fields_for #post.tags do |tag_form|%>
at last, I make it work with below update
<% #post.tags.each do |tag| %>
<%= post_form.fields_for tags,tag do |tag_form|%>
<div class="field">
<%= tag_form.label :name, 'Tag:' %>
<%= tag_form.text_field :name %>
</div>
<% unless tag_form.object.nil? || tag_form.object.new_record? %>
<div class="field">
<%= tag_form.label :_destroy, 'Remove:' %>
<%= tag_form.check_box :_destroy %>
</div>
<% end %>
<% end %>
<% end %>

Resources