0

Rails 4.2

I've created a multi-step wizard for a User model i.e. a visitor to the app registers as a User over a 4 step form. Its working in it's current setup.

However, I've had to use require statements to include several of the wizard related ruby files. As a consequence these files are not auto loaded by Rails.

I'd like to refactor the relevant files so that they follow Rails conventions and are able to be auto loaded.

Current Structure - is working

app/wizards/user.rb User wizard model - runs validations on each step etc

module Wizard
  module User
    STEPS = %w[step1 step2 step3 step4].freeze

    # omitted class implementations, not relevant
    class Base
    end
    class Step1 < Base
    end
    class Step2 < Step1
    end
    class Step3 < Step2
    end
    class Step4 < Step3
    end
  end
end

app/controllers/user_wizards_controller.rb

# I have to require the file above, would like to avoid
require Rails.root.join('app', 'wizards', 'user.rb')

class UserWizardsController < ApplicationController

  # I have to specify the template, would like to avoid
  def step1
    render 'wizards/users/step1'
  end

  # Notice how I have to refer to module/classes above.
  def wizard_user_for_step(step)
    raise InvalidStep unless step.in?(::Wizard::User::STEPS)
 
    "Wizard::User::#{step.camelize}".constantize.new(session[:user_attributes])
  end
end

app/views/wizards/users/step1.html.erb

app/views/wizards/users/step2.html.erb

Attempted Solution

Based on this statement by xfn

The directories in autoload_paths are considered to be root directories, they do not reflect namespacing. For example, the classes below app/models are not under a Models namespace, any namespace has to go within that directory.

The file app/services/doctor_finder.rb for example does not follow autoloading conventions because of that, since it defines Services::DoctorFinder rather than DoctorFinder. Therefore, that file cannot be autoloaded.

I'm going for...

Models

app/wizards/user/user.rb

app/wizards/user/base.rb

app/wizards/user/step1.rb

app/wizards/user/step2.rb

app/wizards/user/step3.rb

app/wizards/user/step4.rb

However, I'm not getting very far. Any ideas?

Community
  • 1
  • 1
Patrick Quigley
  • 404
  • 2
  • 12

1 Answers1

1

If you want to autoload these files move it into e.g services or steps directories like:

 app/services/wizards/user/step1 

and rails should autoload module:

 module Wizards::User
    class Step1
    end
 end

Depend on rails version you will need to add 'services' to autoload path.

Regards views:

 render 'wizards/users/step1'

isn't bad and In my opinion could be consider as good practice.(using render method allow you to pass non global variables to view)

If you want to remove this line you should put views for UserWizardsController to user_wizards/step1.html.xxx

or if you want to have view in wizards/users/step1.html.xxx you should scope your controller in that way:

module Wizards
  class UsersController < ApplicationController
  end
edn
Piotr Galas
  • 4,518
  • 2
  • 21
  • 30