Home > database >  Ruby on Rails 7 Multistep form with multiple models logic
Ruby on Rails 7 Multistep form with multiple models logic

Time:11-28

I am currently struggling with building up a multi step form where every step creates a model instance.

In this case I have 3 models:

  1. UserPlan
  2. Connection
  3. GameDashboard

Since the association is like that:

An user has an user_plan A connection belongs to an user_plan A game_dashboard belongs to a connection

I would like to create a wizard to allow the current_user to create a game_dashboard going through a multi-step form where he is also creating connection and user_plan instance.

For this purpose I looked at Wicked gem and I started creating the logic from game_dashboard (which is the last). As soon as I had to face with form generating I felt like maybe starting from the bottom was not the better solution.

That’s why I am here to ask for help:

What would be the better way to implement this wizard? Starting from the bottom (game_dashboard) or starting from the top (use_plan)?

Since I’m not asking help for code at the moment I didn’t write any controller’s or model’s logic, in case it would be helpful to someone I will put it!

Thanks a lot

CodePudding user response:

The simplest way would be to rely on the standard MVC pattern of Rails.

Just use the create and update controller methods to link to the next model's form (instead of to a show or index view)

E.g.

class UserPlansController < ApplicationController
  ...

  def create
    if @user_plan = UserPlan.create(user_plan_params)
      # the next step in the form wizard process:
      redirect_to new_connection_path(user_id: current_user, user_plan_id: @user_plan.reload.id)
    else
      @user_plan = UserPlan.new(user: current_user)
      render :new
    end    
  end

  ...

  # something similar for #update action
end

For routes, you have two options:

You could nest everything:

# routes.rb

resources :user do
  resources :user_plan do
    resources :connection do
      resources : game_dashboard
    end
  end
end

Pro:

This would make setting your associations in your controllers easier because all your routes would have what you need. E.g.:

/users/:user_id/user_plans/:user_plan_id/connections/:connection_id/game_dashboards/:game_dashboard_id

Con:

Your routes and link helpers would be very long and intense towards the "bottom". E.g.

game_dashboard_connection_user_plan_user_path(:user_id, :user_plan_id, :connection_id, :game_dashboard)

You could just manually link your wizard "steps" together

Pro:

The URLs and helpers aren't so crazy. E.g.

new_connection_path(user_plan_id: @user_plan.id)

With one meaningful URL variable: user_plan_id=1, you can look up everything upstream. e.g.:

@user_plan = UserPlan.find(params['user_plan_id'])
@user = @user_plan.user

Con:

(not much of a "con" because you probably wind up doing this anyway)

If you need to display information about "parent" records, you have to perform model lookups in your controllers first:

class GameDashboardController < ApplicationController
  # e.g. URL: /game_dashboards/new?connection_id=1
  def new
    @connection = Connection.find(params['connection_id'])
    @user_plan = @connection.user_plan
    @user = @user_plan.user
    @game_dashboard = GameDashboard.new(connection: @connection)
  end
end
  • Related