Bonjour,

Pour les besoins d'une application, j'ai besoin de sortir du pattern habituel de RoR.

Ce que je fais

J'ai une liste de voitures (id, brand) avec système de CRUD classique.

# model
class Car < ActiveRecord::Base
  validates :brand, presence: true
end
# controller
def index
  @cars = Car.all
end

def new
  @car = Car.new
end
/ view
= simple_form_for @car do |f|
  = f.input brand

Ce que je veux

Plutôt qu'être dans un CRUD assez classique,
je souhaite avoir dès l'index un formulaire avec tous les véhicules dans des zones de texte (un peu à la méthode des nested fields)

Une solution que j'avais envisager, c'était de faire un modèle parent :
(exemple de code)

# model
class Vehicle  < ActiveRecord::Base
  has_many :cars
  accepts_nested_attributes_for :cars
end

class Car < ActiveRecord::Base
  validates :brand, presence: true
end
# controller
def index
  @cars = Car.all
end

def new
  @vehicle = Vehicle.includes(:cars).where(cars: { id: params[:id] }).first
end
/ view
= simple_form_for @vehicle do |f|
  = f.simple_fields_for :cars do |c|
    = c.input :brand

Dans un soucis de 'perfectionnisme', ça ne m'intéresse pas de créer spécialement une table, et je souhaite savoir s'il y a un moyen plus propre ?

J'ai regardé du côté de la gem Reform de Trailblazer pour créer des "objets virtuels" composé d'une collection de voiture, je galère un peu et du coup je souhaitais avoir l'avis de développeur plus expérimenté :)

(Au delà de ce soucis, je souhaite également créer des formulaires avec des objets qui n'ont parfois aucun rapport, mais avec "1 seul bouton Enregistrer")

1 réponse


Xanatos
Auteur
Réponse acceptée

La solution se cache dans la simplicité.

J'avais rapidement zappé les chapitres sur les helpers de Rails pour la création de formulaire et je suis allé quasi directement sur la gem Simple Form.

Cette gem est très bien pour des formulaires simples & classiques, mais dès que l'on veut faire des formulaires un peu plus élaboré, elle n'offre pas assez de souplesse.

Pour ceux que ça intéresse, une solution (améliorable) que j'ai trouvé, je met le code brute, il est je pense assez simple à compendre.

Routes

resources :cars
match '/cars', to: 'cars#update_all', via: [:patch, :put]

Contrôleur

def index
  @cars = Car.all
end

def update_all

  cars_params = params.require(:cars)  # à améliorer pour ne prendre que les champs autorisés

  # valeur de cars_params
  # { "1" => { "brand" => "Renault" }, "2" => { "brand" => "Peugeot" }, "3" => { "brand" => "Citroen" } }

  if Car.update(cars_params.keys, cars_params.values)
    redirect_to cars_path, :notice  => "Les voitures ont été mises à jour."
  else
    @cars = Car.all
    render :index
  end
end

Vue

= form_tag cars_path, { method: :put } do

  - @cars.each do |car|

    hr

    = fields_for "cars[]", car do |c|

      div
        = c.label(:brand, "Marque")
        = c.text_field(:brand)

  div
    = submit_tag("Mettre à jour")