2011-03-21 20 views
14

¿Hay algún tutorial sobre cómo andamiar un modelo simple que usa relaciones de muchos a muchos?rieles 3 andamios del modelo relacional

+1

Buscando en Google su pregunta me dio esto: http://jrhicks.net/Projects/rails/has_many_and_belongs_to_many.pdf que espero que pueda usar – rsplak

+0

¡Eso fue escrito hace 5.5 años! Dudo que funcione en Rails 3. –

+0

¿Qué es exactamente lo que estás buscando? La visualización de muchos a muchos puede ser complicada. No creo que sea factible generar algo. –

Respuesta

45

Esto es lo que escribí mientras creaba la siguiente testapp paso a paso usando ruby ​​1.9.2 en Rails 3.0.5. También vea 'Gemfile' para las gemas que utilicé (todo Testapp descargable, el enlace está al final en la parte 15). Así que aquí va:

1) ir a un lugar donde se desea crear una aplicación de prueba, a continuación,

rails new mynewtestapp 
cd mynewtestapp 

2) a continuación, añadir 2 modelos que tienen una asociación has_and_belongs_to_many

rails g scaffold book title:string author:string 
rails g scaffold user name:string age:integer 

3) entonces necesitas crear la tabla de unión para esa asociación ... por defecto los rieles buscarán una tabla con el nombre que consiste en los nombres de ambas tablas asociadas en orden alfabético ... así que permite crear una migración para crear dicha tabla

rails g migration createBooksUsers 

4) abrir el archivo de migración generada, que en ese momento se ve como

class CreateBooksUsers < ActiveRecord::Migration 
    def self.up 
    end 

    def self.down 
    end 
end 

5) modificar eso para tener este aspecto

class CreateBooksUsers < ActiveRecord::Migration 
    def self.up 
    create_table :books_users, :id => false do |t| 
     t.integer :book_id 
     t.integer :user_id 
    end 
    end 

    def self.down 
    drop_table :books_users 
    end 
end 

6) añadir la asociación has_and_belongs_to_many al libro y modelos de usuario, así como los nuevos identificadores añadidos por la relación

aplicación/modelo/book.rb

class Book < ActiveRecord::Base 
    attr_accessible :title, :author, :user_ids 
    has_and_belongs_to_many :users 
end 

app/modelo/user.rb

class User < ActiveRecord::Base 
    attr_accessible: :name, :age, :book_ids 
    has_and_belongs_to_many :books 
end 

7) ahora se hacen nuestros modelos y migraciones ... Vamos a crear las tablas

rake db:create 
rake db:migrate 

(así crear podría no ser necesario si usted usa sqlite3 o si ha creado la base de datos para usarla manualmente, este ejemplo funcionará usando sqlite, por lo tanto, no he agregado nada relacionado con la instalación de un sistema de gestión de bases de datos. pero como hay muchos y en realidad todos los que son dignos de ser utilizados están muy bien documentados, encontrará cualquier ayuda sobre eso bastante rápido)

8) ahora decida qué objeto se asignará a qué objeto ... por supuesto puedes hacerlo de las dos maneras ... lo mantendré simple y demostraré que a uno ... digamos que tienes solo unos pocos usuarios y quieres asignarlos a los libros ...

en este punto, Yo diría que busquemos ayuda externa, como binary x sugerido ... pero por simplicidad elegiría la gema simple_form sobre Formtastic. Supongo que todo el mundo tiene sus favoritos ... pero simple_form parece que le dará más libertad en css-styling toda la salida a sus deseos ... por lo que permite instalar simple_form en este punto, simplemente

echo "gem 'simple_form', :git => 'git://github.com/plataformatec/simple_form.git'" >> Gemfile 

para añadir simple_form a su Gemfile, luego ejecute

bundle install 

e instale un formulario simple para su aplicación (es decir,generar config, estilos predeterminados y los archivos de idioma) por

rails g simple_form:install 

9) cuando a modificar nuestros libros forman

los libros forman ahora debería tener este aspecto

app/views/libros/_form. html.erb

01 <%= form_for(@book) do |f| %> 
02  <% if @book.errors.any? %> 
03  <div id="error_explanation"> 
04   <h2><%= pluralize(@book.errors.count, "error") %> prohibited this book from being saved:</h2> 
05  
06   <ul> 
07   <% @book.errors.full_messages.each do |msg| %> 
08   <li><%= msg %></li> 
09   <% end %> 
10   </ul> 
11  </div> 
12  <% end %> 
13  
14  <div class="field"> 
15  <%= f.label :title %><br /> 
16  <%= f.text_field :title %> 
17  </div> 
18  <div class="field"> 
19  <%= f.label :author %><br /> 
20  <%= f.text_field :author %> 
21  </div> 
22  <div class="actions"> 
23  <%= f.submit %> 
24  </div> 
25 <% end %> 

Usando simple_form, podemos simplemente reemplazar una parte del código anterior (líneas 1 y 14 - 24) por lo que todo el archivo se vería así:

01 <%= simple_form_for(@book) do |f| %> 
02  <% if @book.errors.any? %> 
03  <div id="error_explanation"> 
04   <h2><%= pluralize(@book.errors.count, "error") %> prohibited this book from being saved:</h2> 
05  
06   <ul> 
07   <% @book.errors.full_messages.each do |msg| %> 
08   <li><%= msg %></li> 
09   <% end %> 
10   </ul> 
11  </div> 
12  <% end %> 
13  
14  <%= f.input :title %> 
15  <%= f.input :author %> 
16  <%= f.association :users %> 
17  
18  <%= f.button :submit %> 
19  
20 <% end %> 

10) Ahora es posible que desee iniciar la aplicación

rails s 

añadir algunos usuarios, a continuación, añadir un libro y y no es su primera forma has_and_belongs_to_many: first simple_form form without special effects

11) Bueno, eso puede que aún no sea lo más bonito que se debe mirar, pero una simple adición de una hoja de estilo ayudará un poco ... crear un nuevo archivo

public/stylesheets/simple_form.css 

y pegar las siguientes líneas en que

/* public/stylesheets/simple_form.css */ 
.simple_form label { 
    float: left; 
    width: 100px; 
    text-align: right; 
    margin: 2px 10px; 
} 

.simple_form div.input { 
    margin-bottom: 10px; 
} 

.simple_form div.boolean, .simple_form input[type='submit'] { 
    margin-left: 120px; 
} 

.simple_form div.boolean label, .simple_form label.collection_radio, .simple_form label.collection_check_boxes{ 
    float: none; 
    margin: 0; 
} 

.simple_form .error { 
    clear: left; 
    margin-left: 120px; 
    font-size: 12px; 
    color: #D00; 
    display: block; 
} 

.simple_form .hint { 
    clear: left; 
    margin-left: 120px; 
    font-size: 12px; 
    color: #555; 
    display: block; 
    font-style: italic; 
} 

vuelva a cargar la página y ... ... Tadaa primera huelga ... after adding a default simple_form stylesheet

12), y si no te gusta múltiple -Elección-cuadros de lista sólo tiene que ir de nuevo a los libros forman

app/views/libros/_form.html.erb

y modificar la línea

15  <%= f.input :author %> 

ligeramente para

15  <%= f.input :author, :as => :check_boxes %> 

para hacer casillas fuera de la lista de la caja .... pero ... Ewww .... mira esto: left to right checkbox display

13) algo parece un poco incorrecto ... se sabe que la presentación de izquierda a derecha de las opciones causa problemas a los novatos simples de vez en cuando, pero en realidad es un problema fácil de arreglar

y además de ese pequeño problema de formato, es posible que también querer ver la edad de Usuarios detrás de su nombre en los apoyos, como 'Tom (25)'

... así que vamos a hacer 3 soluciones rápidas

a) uncomment y establecer 2 opciones en config/inicializadores/simple_form.rb en para envolver cada casilla con un div y colocar el conjunto de casillas de verificación dentro de un conjunto de campos

# You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none. 
    config.collection_wrapper_tag = :fieldset 

    # You can wrap each item in a collection of radio/check boxes with a tag, defaulting to none. 
    config.item_wrapper_tag = :div 

b) modificar nuestra hoja de estilo simple_form.css un poco, como en el complemento:

fieldset { border: 0; } 

...a menos que prefiera un borde grande y feo alrededor del fieldset

c) cree el método 'to_label' en nuestro modelo de usuario, ya que 'to_label' es por defecto el primer método que busca simple_form para obtener un String- representación para mostrar un objeto. Por un extraño incidente, nuestro modelo de usuario tiene una columna llamada 'nombre'. Como el nombre también es un método que simple_form busca en un modelo, tuvimos suerte de que esta aplicación haya funcionado hasta el momento. Si en lugar de eso hubiésemos llamado el nombre de la columna de nombre, Rails no habría enumerado los nombres de usuario, sino las representaciones de ruby-object por defecto (por ejemplo, < #Usuario: 521369846>). Supongo que la suerte ;-)

app/modelos/user.rb

class User < ActiveRecord::Base 
    has_and_belongs_to_many :users 

    def to_label 
    "#{name} (#{age})" 
    end 

end 

y la edición forma consigue un buen aspecto ... nice and cozy edit view

14) Ahora sólo la vista espectáculo necesita mostrar los propietarios de libros ... eso no es demasiado difícil tampoco, basta con abrir el show-vista

app/views/libros/show.html.erb

y añadir li nes 13-16 para que aparezcan las bookowners:

01 <p id="notice"><%= notice %></p> 
02  
03 <p> 
04  <b>Title:</b> 
05  <%= @book.title %> 
06 </p> 
07  
08 <p> 
09  <b>Author:</b> 
10  <%= @book.author %> 
11 </p> 
12  
13 <p> 
14  <b>Who owns a copy?</b> 
15  <%= @book.users.map {|x| x.to_label}.join ', ' %> 
16 </p> 
17  
18 <%= link_to 'Edit', edit_book_path(@book) %> | 
19 <%= link_to 'Back', books_path %> 

y por último pero no menos importante ... el espectáculo vista Who owns a book?

15) bien, tanto para un rápido tutorial para HABTM o en palabras asociaciones has_and_belongs_to_many en rieles. He puesto mi examen de la aplicación que creé al escribir esta línea en https://1drv.ms/u/s!Alpu50oGtUZq7AiJkL08QqBiMAjb

+0

nice write up! bastante completo – Andrew

+0

¿Esto sigue siendo válido en los carriles 3.2.3? Siento que he seguido los pasos correctamente, pero aparece un error después del paso 11 (cuando intento crear un libro) que dice "No se pueden asignar en masa los atributos protegidos". Si solo lo estoy haciendo mal, por favor ignóralo. :) – timfreilly

+0

@timfreilly: no he probado esto en los carriles 3.2.3, pero como "todo es nuevo", yo. mi. Rails y Simple-Form, supongo que algunas cosas son diferentes. Tristemente no he tenido la oportunidad de trabajar con Rails 3.1+, así que no puedo decirlo. Intenta buscar en google el mensaje de error que mencionaste, estoy seguro de que encontrarás una pista para llegar a una solución. – Ingo

Cuestiones relacionadas