How to Generate The Form for an Existing Model in Rails

How do you generate the form for an existing model in Rails?

This may sound silly, but hear me out... I've done things like this a few times myself when I wanted to start clean. Following is a script that will read your schema and produce the necessary generate commands to reproduce it:

require 'rubygems'
require 'active_support/core_ext'
schema = File.read('db/schema.rb')
schema.scan(/create_table "(\w+)",.*?\n(.*?)\n end/m).each do |name, ddl|
puts "rails generate scaffold #{name.classify} " +
ddl.scan(/t\.(\w+)\s+"(\w+)"/).
reject {|type,name| %w(created_at updated_at).include? name}.
map {|type,name| "#{name}:#{type}"}.join(' ')
end

If you run this, you will get a series of commands. In a new directory, create a new rails application, and then run these commands (simply copying and pasting them will do). Grab the files you want. Delete the directory when you are done.

Rails generate forms based on model

https://github.com/justinfrench/formtastic

Allows you to do this.

Rails: Add form from different model

Normally, when rendering a partial like:

<% render partial: 'form', object: @project_message %>

Because you are passing the @project_message as the specially-named object parameter, this creates a special variable with the name of the partial - in this case, form.

Therefore in the partial, you could reference this variable:

<%= form_with(model: form, local: true) do |form| %>

...However, in this case, it doesn't really make sense to call the local variable form! So I would be inclined to use whatever name you're passing it in as - for example, you could do:

<% render partial: 'form', project_message: @project_message %>

And then in the partial:

<%= form_with(model: project_message, local: true) do |form| %>

For more info, see: http://guides.rubyonrails.org/layouts_and_rendering.html#passing-local-variables

Make a form_for add data to existing model (rails)

May be you can decide the update action based on params.

def update
if current_user
@user = current_user
else
@user = User.find(params[:id])
end

if params[:user][:password]
# or other actions will save new password?
@user.password_hash = nil
notice = "Password has been changed!"
else
notice = "User profile has been changed!"
end

if @user.update_attributes(params[:user])
redirect_to @user, :notice => notice
else
render "edit"
end

end

Ruby on Rails: how to make a form for associated models (nested)

Lets start with the models:

class Project < ApplicationRecord
has_many :todos
accepts_nested_attributes_for :todos
end

class Todo < ApplicationRecord
belongs_to :project
end

accepts_nested_attributes_for lets you create or modify several nested Todo records at once when creating or updating a Project.

# will update 2 todos at once
@project.update(
todos_attributes: [ { id: 1, isComplete: true }, { id: 2, isComplete: false }]
)

We can use fields_for to create nested inputs for todos:

<%= f.form_for(@project) do |f| %>
<%= f.fields_for(:todos) do |tf| %>
<%= tf.check_box :isCompleted %>
<% end %>
<% end %>

This generates fields for todos nested under the key todos_attributes. We can whitelist them by using a hash key containing a array of permitted attributes.

class ProjectsController < ApplicationController
before_action :set_project, only: [:show, :edit, :update, :destroy]

def new
@project = Project.new
# this seeds the project with 3 empty tasks
# otherwise we don't have any inputs.
3.times { @project.todos.new }
end

def create
@project = Project.new(project_params)
if @project.save
# ...
else
# ...
end
end

def update
if @project.update(project_params)
# ...
else
# ...
end
end

private

def set_project
@project = Project.find(params[:id])
end

def project_params
params.require(:project)
.permit(:foo, :bar,
todos_attributes: [:isCompleted, :text]
)
end
end

You can create a form for each project by creating a partial which uses a local instead of an instance variable:

# app/views/projects/_form.html.erb
<%= f.form_for(local_assigns[:project] || @project) do |f| %>
<%= f.fields_for(:todos) do |tf| %>
<%= tf.check_box :isCompleted %>
<% end %>
<% end %>

# app/views/projects/index.html.erb
<% @projects.each do |project| %>
<%= render partial: 'projects/form', project: project %>
<% end %>

You can reuse the same partial for the other views as well:

# app/views/projects/new.html.erb
<%= render partial: 'projects/form' %>

# app/views/projects/edit.html.erb
<%= render partial: 'projects/form' %>

Building new Model A form from Model B attributes

First I set the variables, then I was able to iterate over them. Is this is the rails way? I don't know but it works and the max number of objects it would iterate over is 20.

@routine = Routine.includes(:routine_set_reps).find_by(id: params[:routine_id])
@workout = current_user.workouts.new(@routine.attributes.extract!('name', 'sport'))

c = r.count
r = @routine.routine_set_reps
w = @workout.workout_set_reps
c.times{ w.new }
r.zip(w).each do |routine, workout|
workout.exercise_id = routine.exercise_id
workout.set = routine.set
workout.rep = routine.rep
workout.weight = routine.weight
workout.weight_unit = routine.weight_unit
end

Probably could refactor this into a method and just call it but for now working is working.

Just fyi I use = instead of ||= because the workout_set_reps will always be new. Is this right? I'm not positive, but leave a comment if you believe differently or agree with a reason.

Rails: How to run `rails generate scaffold` when the model already exists?

TL;DR: rails g scaffold_controller <name>

Even though you already have a model, you can still generate the necessary controller and migration files by using the rails generate option. If you run rails generate -h you can see all of the options available to you.

Rails:
controller
generator
helper
integration_test
mailer
migration
model
observer
performance_test
plugin
resource
scaffold
scaffold_controller
session_migration
stylesheets

If you'd like to generate a controller scaffold for your model, see scaffold_controller. Just for clarity, here's the description on that:

Stubs out a scaffolded controller and its views. Pass the model name,
either CamelCased or under_scored, and a list of views as arguments.
The controller name is retrieved as a pluralized version of the model
name.

To create a controller within a module, specify the model name as a
path like 'parent_module/controller_name'.

This generates a controller class in app/controllers and invokes helper,
template engine and test framework generators.

To create your resource, you'd use the resource generator, and to create a migration, you can also see the migration generator (see, there's a pattern to all of this madness). These provide options to create the missing files to build a resource. Alternatively you can just run rails generate scaffold with the --skip option to skip any files which exist :)

I recommend spending some time looking at the options inside of the generators. They're something I don't feel are documented extremely well in books and such, but they're very handy.



Related Topics



Leave a reply



Submit