Rails: Scaffold para automaticamente fazer um-para-muitos
-
20-08-2019 - |
Pergunta
Não tenho certeza se eu estou lendo este direito , mas parece que Andaime não vai fazer uma relação de um-para-muitos na sua totalidade. Por exemplo, se eu criar messages
com andaime e então eu quero comments
sobre aqueles messages
(um message
-> muitos comments
), eu tenho que passar e mudar tudo. Por exemplo, eu tenho que mudar isso em vista comment
do new
<% form_for(@comment) do |f| %>
a esta ??p>
<% form_for([@message, @comment]) do |f| %>
e altere a ação para configurar o @message
var ... entre outras coisas.
Isto não pode actualmente ser feito automaticamente com andaime, certo?
Solução
This is true, but, it's not the end of the story. There are at least two alternatives to Scaffold that both work quite well and automatically pick up on relationships between classes (based on your ActiveRecord relationship indicators like has_many). One of these alternatives is Streamlined and the other is ActiveScaffold.
They're mainly helpful for entering in data that your system requires that is not user entered data. For example, I use them for administrative tasks on tables where there's no point in building a complete UI for CRUD when one of the scaffold alternatives will do the job just fine for a seldom used feature. You wouldn't want to use them for comments on messages though.
Outras dicas
Yes. Scaffold works for a model and related controller. It does not take care of or work with relationships.
Scaffold's primary objective is to get CRUD going on a model using a controller and related views. That's all. Any other requirement like relationships has to be coded manually.
Note that there are projects like Hobo for Rails which allow you to keep your fields and associations within the model itself. You can't scaffold associations, but it's pretty close.
You end up paying for this sugar by having a lot more of the application built behind your back. Instead of rolling your own, you're usually subtracting out what you need from a large bank of prebuilt behaviors.
You don't need a heavy rails admin framework to get one-to-many relationships working.
You can use scaffolding to get most of the way there.
A little more work in the controller and _form view will get you the rest of the way there.
Here's how...
Story: Select a beer for a developer
In order to select a beer for a developer
As an admin
I want a mainly scaffolded interface to select that beer
Scenario 1: Select beer for new developer
Given I have clicked the <new> button and entered the developer's name
When I click the beer dropdown
Then I should be presented with a list of beers to choose from
And that beer will be saved when I click <ok>
Scenario 2: Select a different beer for existing developer
Given I have clicked the <edit> button on the index page for a particular developer
When I click the beer dropdown
Then I should be presented with a list of beers to choose from
And that beer will be saved when I click <ok>
Assuming we have a beers table:
create_table "beers", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
And a developers table that has a foreign key (beer_id) referencing the beers table:
create_table "developers", force: true do |t|
t.string "name"
t.integer "beer_id"
t.datetime "created_at"
t.datetime "updated_at"
end
We can use scaffolding to create both tables:
$ rails g scaffold beer name
$ rails g scaffold developer name beer_id:integer
The scaffold command creates the controllers and views for each model.
We will need to modify our controllers and views a little bit to get the dropdown menu to select a beer for each developer:
app/views/developers/_form.html.erb
Replace the generated text_field and label for beer_id with the following:
<div class="field">
<%= f.label :beer_id %><br />
<%= collection_select(:developer, :beer_id, @beers, :id, :name, {:prompt => false}) %>
</div>
app/controllers/developer_controller.rb
Edit the controller's new and edit methods:
# GET /developers/new
def new
@developer = Developer.new
@beers = Beer.all
respond_to do |format|
format.html # new.html.erb
end
end
# GET /developers/1/edit
def edit
@beers = Beer.all
respond_to do |format|
format.html # new.html.erb
end
end
Screen Shots
Notes
Rails scaffolding is great. Look at all the files that it creates for you:
$ be rails g scaffold beer name
invoke active_record
create db/migrate/20140912144218_create_beers.rb
create app/models/beer.rb
invoke rspec
create spec/models/beer_spec.rb
invoke factory_girl
create spec/factories/beers.rb
invoke resource_route
route resources :beers
invoke scaffold_controller
create app/controllers/beers_controller.rb
invoke erb
create app/views/beers
create app/views/beers/index.html.erb
create app/views/beers/edit.html.erb
create app/views/beers/show.html.erb
create app/views/beers/new.html.erb
create app/views/beers/_form.html.erb
invoke rspec
create spec/controllers/beers_controller_spec.rb
create spec/views/beers/edit.html.erb_spec.rb
create spec/views/beers/index.html.erb_spec.rb
create spec/views/beers/new.html.erb_spec.rb
create spec/views/beers/show.html.erb_spec.rb
create spec/routing/beers_routing_spec.rb
invoke rspec
create spec/requests/beers_spec.rb
invoke helper
create app/helpers/beers_helper.rb
invoke rspec
create spec/helpers/beers_helper_spec.rb
invoke jbuilder
create app/views/beers/index.json.jbuilder
create app/views/beers/show.json.jbuilder
invoke assets
invoke coffee
create app/assets/javascripts/beers.js.coffee
invoke scss
create app/assets/stylesheets/beers.css.scss
invoke scss
create app/assets/stylesheets/scaffolds.css.scss
All you have to do is know which files to modify when you want more than basic CRUD operations.
Hope that helps. ~ Lex
Scaffolds are scaffolds. When you want anything other than a CRUD on a table (which is what a scaffold is/does), you need to alter the generated scaffolding code, or roll your own.