Criar uma lista ou uma lista de objectos em Ruby nos carris
estou tentando tornar possível para os usuários de uma aplicação web que estou construindo para criar listas de objetos que eles criaram.
por exemplo, o utilizador tem uma lista de objectos como Mercearias que podem ser qualquer coisa, desde maçãs a laranjas a pop-tarts.
Então gostaria que fosse possível devolver todas as compras adicionadas à base de dados pelo Usuário e criar uma lista selecionando aquelas que deveriam estar em seu supermercado. lista.de preferência, este seria um estilo de modo a que eles pudessem clicar em opções para aqueles que queriam e, em seguida, clicar em save para criar uma nova lista.
eu procurei em belongs_to, has_many relacionamentos e tentei criar um objeto de lista que tem muitas compras, mas eu não consigo descobrir a forma parte desta estratégia. Agradecia qualquer conselho. Obrigado!
Aqui está o código que eu tenho atualmente, Eu o omiti originalmente porque eu não acho que eu estou no direito caminho, mas aqui está de qualquer forma apenas em caso/fornecer mais contexto:Modelo De Mercearia:
class Item < ApplicationRecord
belongs_to :list, optional: true
end
List Model
class List < ApplicationRecord
has_many :items
end
O controlador da lista
class ListsController < ApplicationController
before_action :authenticate_user!
layout 'backend'
def index
@lists = List.where(user_id: current_user.id)
end
def show
end
def new
@list = List.new
end
def edit
end
def create
@list = List.new(list_params)
@list.user = current_user
if @list.save
redirect_to list_path(@list.id), notice: 'List was successfully created.'
else
redirect_to list_path(@list.id), notice: 'List was not created.'
end
end
def update
respond_to do |format|
if @list.update(list_params)
format.html { redirect_to @list, notice: 'List was successfully updated.' }
format.json { render :show, status: :ok, location: @list }
else
format.html { render :edit }
format.json { render json: @list.errors, status: :unprocessable_entity }
end
end
end
def destroy
@list.destroy
respond_to do |format|
format.html { redirect_to lists_url, notice: 'List was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Never trust parameters from the scary internet, only allow the white list through.
def list_params
params.require(:list).permit(:name, :items)
end
end
não sei o que fazer sobre a forma-estava a tentar algo como http://apidock.com/rails/ActionView/Helpers/FormHelper/check_box
2 answers
:accepts_nested_attributes_for
.
Para dar um exemplo, aqui está como eu iria estruturar os modelos:
class List < ApplicationRecord
has_many :list_items, inverse_of: :list
has_many :items, through: :list_items
# This allows ListItems to be created at the same time as the List,
# but will only create it if the :item_id attribute is present
accepts_nested_attributes_for :list_items, reject_if: proc { |attr| attr[:item_id].blank? }
end
class Item < ApplicationRecord
has_many :list_items
has_many :lists, through: :list_items
end
class ListItem < ApplicationRecord
belongs_to :list, inverse_of: :list_items
belongs_to :item
end
Com essa estrutura de modelo no lugar, aqui está um exemplo da vista para criar uma nova lista.
<h1>New List</h1>
<%= form_for @list do |f| %>
<% @items.each_with_index do |item, i| %>
<%= f.fields_for :list_items, ListItem.new, child_index: i do |list_item_form| %>
<p>
<%= list_item_form.check_box :item_id, {}, item.id, "" %> <%= item.name %>
</p>
<% end %>
<% end %>
<p>
<%= f.submit 'Create List' %>
</p>
<% end %>
Para explicar o que está a acontecer aqui, @items
é uma variável pré-carregada para ter todos os itens que podem ser adicionados a um lista. Faço um loop através de cada Item e passo-o manualmente para o método do FormBuilder fields_for
.
Porque faço isto manualmente, tenho de especificar o :child_index
ao mesmo tempo, caso contrário cada opção obteria o mesmo atributo de nome (ou seja name="list[list_item_attributes][0][item_id]"
) que o item anterior e eles sobrepor-se-iam ao serem submetidos ao servidor.
E o método do Construtor de formulários check_box
tem a seguinte declaração:
def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
Assim, na forma acima, eu substituo esses valores predefinidos de modo que, quando uma opção está assinalada, tem o valor de item.id
e, se não estiver assinalada, o valor está em branco. Combine isto com a declaração de accepts_nested_attributes_for
no modelo da lista, onde dizemos que deve ser rejeitado se o :item_id
estiver em branco, e obtemos o resultado de apenas criar ListItems para os itens verificados.
A última coisa a fazer isto funcionar, é permitir os atributos aninhados no controlador, assim:
def allowed_params
params.require(:list).permit(list_items_attributes: [:item_id])
end
Mostrar uma lista de opções em vez de várias opções
Eu simplesmente implementei o seguinte
<% form_for @list do |f| %>
<% Item.all.each do |item|
<%= f.check_box(:items, { :multiple => true }, item.id) %>
<% end %>
<% end %>
Em que ponto eu tive o erro de que não havia nenhum list_id atribuído. Eu fiz uma migração a fim de adicionar attirbute "list_id" ao modelo de Item, e isso corrigiu-o e tudo funciona como eu queria.
Algum problema?