Search code examples
ruby-on-railsrubysessionruby-on-rails-4.2apartment-gem

Rails - Session Variable Not Persisting Through Apartment Switch


I have a situation.

>rails -v
Rails 4.2.4

>ruby -v
ruby 2.1.8p440 (2015-12-16 revision 53160) [i386-mingw32]

I am building a multi-tenant Time Entry solution using the Apartment gem. Here's the flow. I'm stuck.

1) User arrives at the signup page, which creates the tenant. Here's the controller:

  def new
    @tenant = Tenant.new
  end

  def create
    @tenant = Tenant.new(tenant_params)
    session[:tenant_attributes] = @tenant.attributes

    if @tenant.save

      flash[:success] = "Org ID #{session[:tenant_attributes]["org_identifier"]} created for #{session[:tenant_attributes]["org_name"]} successfully!"
      # Start a job for creating the tenant: this is handled in the model?
      # Apartment::Tenant.switch!("#{session[:tenant_attributes]["org_identifier"]}")
      redirect_to new_user_url(:subdomain => "#{session[:tenant_attributes]["org_identifier"]}")  #new_user_path
    else
      render :new
    end
  end

And the view:

<% provide(:title, 'Sign up') %>
<h1>Welcome!</h1>
<p class="center">
  Make time entry easy, for once.
</p>
<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_for (@tenant) do |f| %>
        <%= render 'shared/tenant_error_messages' %>

        <%= f.label :creator_email, "What is your email address?" %>
        <%= f.email_field :creator_email, class: 'form-control' %>

        <%= f.label :org_name, "What is the name of your organization?" %>
        <%= f.text_field :org_name, class: 'form-control' %>

        <%= f.label :org_identifier, "Please choose an abbreviated Org ID" %>
        <%= f.text_field :org_identifier, class: 'form-control' %>

        <%= f.submit "Create your own Org", class: "btn btn-primary" %>

    <% end %>
  </div>
</div>

As you can see, this is set to redirect to the new_user_url helper passing a subdomain equal to the new org_identifier (the tenant that was just created.)

2) Upon correct info submission, the redirect happens after the tenant is created. I've confirmed creation is happening. I've confirmed the redirect is correct. Then the session variable empties itself.

The users controller:

def new
    # Instantiate a new user object at the open of the 'new' view
    @user = User.new

  end

 def create
    # This is the method conducted at the submission of the form and instantiates/saves its own user object
    @user = User.new(user_params)
    if @user.save
      log_in @user
      flash[:success] = "Welcome to the Time Entry Solution!"
      if @user.site_id == "nil"
        redirect_to new_client_path #(:subdomain => session[:tenant_attributes]["org_identifier"])
      else
        redirect_to current_user
      end

    else
      render 'new'
    end
  end

The users/new view:

<% provide(:title, 'Sign up') %>
<center><p>
  Tell us more about you.
</p>
</center>
<div class="row">
  <div class="col-md-6 col-md-offset-3">
  <% if session[:tenant_attributes] %>

    <h2><%= session[:tenant_attributes] %></h2>
    <h2><%= session[:tenant_attributes] %></h2>
        <% else %>
    <h2> The session variable is empty.</h2>
<% end %>

    <%= form_for (@user) do |f| %>
        <%= render 'shared/error_messages' %>

        <%= f.hidden_field :email, :value => session[:tenant_attributes]["creator_email"] %>

        <%= f.label :first_name %>
        <%= f.text_field :first_name, class: 'form-control' %>

        <%= f.label :last_name %>
        <%= f.text_field :last_name, class: 'form-control' %>

        <%= f.label :password %>
        <%= f.password_field :password, class: 'form-control' %>

        <%= f.label :password_confirmation, "Confirmation" %>
        <%= f.password_field :password_confirmation, class: 'form-control' %>

        <%= f.submit "Create an org ID", class: "btn btn-primary" %>

    <% end %>

  </div>
</div>

When I submit the subsequent form - which includes a hidden field with the email parameter as the session value I want - I get "Email is invalid."

--- !ruby/hash:ActionController::Parameters
utf8: "✓"
authenticity_token: IAEe2EyvrGFa9gMp2X0WnlBzMHF9WdDXhVIs5s3vPkK54xqgICp3T8S/tXQiQnKYqr2CVTH7+0H9G4SaZNGoDQ==
user: !ruby/hash:ActionController::Parameters
  email: ''
  first_name: Anthony
  last_name: Gardner
  password: Password12345!
  password_confirmation: Password12345!
commit: Create an org ID
controller: users
action: create

I've looked through the Apartment gem doc and scoured the web. I can't see any reason why this should be failing. But of course, I'm sure it's right in front of my face. Any help would be appreciated.

UPDATE:

I found this solution that I will be trying, setting domain of the cookie store to all then checking inside the app controller afterward. I'm not using devise, but we'll see if it works.


Solution

  • Found the answer here: Share session (cookies) between subdomains in Rails?

    The problem was in our session_store.rb. We weren't taking into account that by setting domain: :all, we were disregarding the default TLD length of 1. We were using lvh.me instead of localhost.

    Hope this helps others!