I'm searching for quite some time answer for this but solutions which worked out in other situation not working in my case.
PROBLEM 1: When clicking button "Dodaj skladnik" or "Dodaj krok" I get multiple fields instead of one ( sometimes 2 sometimes 3 sometimes even 40)
I spent so far 3 hours trying to troubleshoot this but I have no idea why it works this way
When I hit ctrl+f5 it works but just one time .... if I try to use form again or reload issue still occurs
I have NO duplicate entries of coccon itself.
amon@AMUNET /app/amanda $ grep -rnw . -e 'cocoon'
Plik binarny ./tmp/cache/assets/sprockets/v3.0/7e/7e5wAAtpwJITUTZozWduRq866c-VsC2gAZvJOcVZmPo.cache pasuje do wzorca
Plik binarny ./tmp/cache/assets/sprockets/v3.0/0l/0l98NX_hEbCP2xKSXIBRKAyLnEDTcUK6gyw5MyNYbPo.cache pasuje do wzorca
Plik binarny ./tmp/cache/assets/sprockets/v3.0/rt/rtICrPE1OuOezvTCGzwYnqRsSHfhoYmMhu8dQSfP-is.cache pasuje do wzorca
./tmp/cache/assets/sprockets/v3.0/V1/V1yaq6iLPp3CDZSltLooShZ6SFBM5vWEjQhQSmoNWEU.cache:3:I"environment-version:ETTI"environment-paths;TTI"rails-env;TTI"Zprocessors:type=application/javascript&file_type=application/javascript&pipeline=self;TTI"{file-digest:///home/amon/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/cocoon-1.2.10/app/assets/javascripts/cocoon.js;TTF
./app/assets/javascripts/application.js:13://= require cocoon
./Gemfile:37:gem 'cocoon', '~> 1.2', '>= 1.2.10'
./Gemfile.lock:50: cocoon (1.2.10)
./Gemfile.lock:183: cocoon (~> 1.2, >= 1.2.10)
Some of code: application.js
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require cocoon
//= require_tree .
recipes_controller.rb
class RecipesController < ApplicationController
before_action :find_recipe, only: [:show, :edit, :update, :destroy]
def index
@recipe = Recipe.all.order("created_at DESC")
end
def show
end
def new
@recipe = Recipe.new
end
def create
@recipe = Recipe.new(recipe_params)
if @recipe.save
redirect_to @recipe, notice: "Przepis zostal dodany"
else
render 'new'
end
end
def edit
end
def update
if @recipe.update(recipe_params)
redirect_to @recipe
else
render 'edit'
end
end
def destroy
@recipe.destroy
redirect_to root_path, notice: "Przepis zostal usuniety"
end
private
def recipe_params
params.require(:recipe).permit(:tittle, :description, :image, ingredients_attributes: [:id, :name, :_destroy], directions_attributes: [:id, :step, :_destroy] )
end
def find_recipe
@recipe = Recipe.find(params[:id])
end
end
_form.html.haml
=simple_form_for @recipe, html: {multipart: true} do |f|
- if @recipe.errors.any?
#errors
%p
= @recipe.errors.count
Prevent this recipe from saving
%ul
- @recipe.errors.full_messages.each do |msg|
%li= msg
.panel-body
= f.input :tittle, input_html: { class: 'form-control' }
= f.input :description, input_html: { class: 'form-control' }
= f.input :image, input_html: { class: 'form-control' }
.row
.col-md-6
%h3 Skladniki
#ingredients
= f.simple_fields_for :ingredients do |ingredient|
= render 'ingredient_fields', f: ingredient
.links
= link_to_add_association 'Dodaj skladnik', f, :ingredients, class: "btn btn-default add-button"
.col-md-6
%h3 Wskazowki
#directions
= f.simple_fields_for :directions do |direction|
= render 'direction_fields', f: direction
.links
= link_to_add_association 'Dodaj krok', f, :directions, class: "btn btn-default add-button"
= f.button :submit, class: "btn btn-primary"
application.html.haml
!!! 5
%html
%head
%title Amanda project
= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true
= javascript_include_tag 'application', 'data-turbolinks-track' => true
= csrf_meta_tags
%body
%nav.navbar.navbar-default
.container
.navbar-brand= link_to "Amanda project", root_path
%ul.nav.navbar-nav.navbar-right
%li= link_to "Dodaj nowy przepis", new_recipe_path
.container
- flash.each do |name, msg|
= content_tag :div, msg, class: "alert"
= yield
_ingredient_fields.html.haml
.form-inline.clearfix
.nested-fields
= f.input :name, input_html: { class: "form-input form-control" }
= link_to_remove_association "Usun", f, class: "form-button btn btn-default"
recipe.rb (Model)
class Recipe < ApplicationRecord
has_many :ingredients
has_many :directions
accepts_nested_attributes_for :ingredients,
reject_if: proc { |attributes| attributes['name'].blank? },
allow_destroy: true
accepts_nested_attributes_for :directions,
reject_if: proc { |attributes| attributes['step'].blank? },
allow_destroy: true
validates :tittle, :description, :image, presence: true
has_attached_file :image, styles: { :medium => "400x400#" }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
end
PROBLEM 2 Also I have problem with saving it. Even when I fill multiple inupts for ingredients and directions I get message
Ingredients recipe must exist
It is huge blocking point for me now so please help.
As explained in the documentation, when using rails 5 you should write your association differently:
has_many :ingredients, inverse_of: :recipe
In short: since rails 5 a belongs_to relation is by default required. While this absolutely makes sense, this also means associations have to be declared more explicitly. When saving nested items, theoretically the parent is not yet saved on validation, so rails needs help to know the link between relations.
The first error sounds like a turbolinks error: somehow you include the application.js
or cocoon.js
multiple times (e.g. if you put it at the bottom of the page --not visible from the code you showed, but this would explain it). Turbolinks will replace the complete body-contents but not the head, and so any javascript in the body will be loaded multiple times (navigating, following links), until you actually refresh the page.