Skip to content

Instantly share code, notes, and snippets.

@VictorTpo
Last active May 15, 2017 18:04
Show Gist options
  • Save VictorTpo/d928b9a692a5ffce6a4492f7660b43fa to your computer and use it in GitHub Desktop.
Save VictorTpo/d928b9a692a5ffce6a4492f7660b43fa to your computer and use it in GitHub Desktop.

How to Nested

Let's imagine we want to assign pokemons to trainers.

We are creating a new_trainer form with checkboxes for each pokemon and their names next a checkbox to assign them to this new trainer, like this:

  • Salameche
  • Ratata
  • Roucool

So we've got this :

Models

class Pokemon
	has_many :pokeballs
	has_many :trainers, through: :pokeballs
end

class Pokeball
	belongs_to :pokemons
	belongs_to :trainers
end

class Trainer
	has_many :pokeballs
	has_many :pokemons, through: :pokeballs
end

Controllers

class TrainersController < ApplicationController
	def new
		@trainer = Trainer.new
	end

	def create
		@trainer = Traner.new(params[:trainer])
		if @trainer.valid?
			@trainer.save
		else
			render 'new'
		end
	end
end

Views

= form_for @trainer do |f|

Let's do this !

Models

class Trainer
	has_many :pokeballs
	has_many :pokemons, through: :pokeballs

	accepts_nested_attributes_for :pokeballs, allow_destroy: true

	attr_accessible :pokeballs_attributes # since Rails 4 it's done with strong params
end

Controller

class TrainersController < ApplicationController
	def new
		@trainer = Trainer.new
		build_pokeballs
	end

	def create
		@trainer = Traner.new(params[:trainer])
		if @trainer.valid?
			@trainer.save
		else
			build_pokeballs
			render 'new'
		end
	end

	private

	def build_pokeballs
		Pokemon.find_each do |pokemon|
			@trainer.pokeballs.build(pokemon: pokemon) unless pokemon_already_join(pokemon)
        end
	end

	def pokemon_already_join(pokemon)
		@trainer.pokeballs.map(&:pokemon_id).include?(pokemon.id)
	end
end

View

= form_for @trainer do |f|
	= f.fields_for :pokeballs, f.object.pokeballs.sort_by(&:pokemon_id) do |f_p|
		- pokemon = f_p.object.pokemon
		= f_p.hidden_field :pokemon_id, value: pokemon.id
		= f_p.check_box :_destroy, { checked: pokemon_checked?(@trainer, f_p.index.to_s) }, 0, 1
		= f_p.label :_destroy, pokemon.name

Helper

# ugly part :s
def pokemon_checked?(trainer, form_index)
	return trainer.pokemons.map(&:id).include?(pokemon.id) if @trainer.pokemons.present?
	params[:trainer].present? ? destroy?(form_index) : false
end

def destroy?(form_index)
	params[:trainer][:pokeballs_attributes][form_index]['_destroy'] == '0'
end

Copie de droite par MAS & VIT

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment