4

Hi I'm hacking around Rails the last 8 months so don't truly understand a number of things. I've seen and used helper methods that set the current_user etc. and am now trying to replicate something similar.

I'm trying to set a global value in the application controller for the current company the user is in. I know I'm doing it wrong but I can't quite figure out how to solve it or even if I'm approaching it correctly. I want it so that when the user clicks on a company, the global variable is set to the id of the company they are in. Then in any other sub-model, if I want info on the company, I use the global variable to retrieve the company object with that id.

The code that's causing the problem is in my navbar in application.html.erb

<li><%= link_to "Company", company_path, :method => :get %></li>

This works when I'm using the companies controller etc. But when I try use any other controller I'm getting the error

ActionController::UrlGenerationError in Employees#index

No route matches {:action=>"show", :controller=>"companies"} missing required keys: [:id] 

which as I understand it means it can't render the url because no company id parameter is being passed?

I was trying to hack a helper method I used in another project (for getting the current_user) but have realised that it uses the session to extract the user.id to return a user object. Here's my attempt at the helper method in application_controller.rb

def current_company
  @company = Company.find_by_id(params[:id])
end

I'm not able to get the current company from the session so my method above is useless unless the company id is being passed as a parameter.

I've thought about passing the company id on every sub-model method but

  1. I'm not 100% sure how to do this
  2. It doesn't sound very efficient

So my question is am I approaching this correctly? What's the optimal way to do it? Can I create a helper method that stores a global company id variable that gets set once a user accesses a company and can then be retrieved by other models?

I probably haven't explained it too well so let me know if you need clarification or more info. Thanks for looking.

Edit 1

Made the changes suggested by Ruby Racer and now I have:

application.html.erb

 <%unless current_page?(root_path)||current_page?(companies_path)||current_company.nil? %>

   <li><%= link_to "Company", company_path, :method => :get %></li>

This is not displaying the link in the navbar, I presume because current_company is nil (the other two unless statements were fine before I added current_company.nil?

I'm setting the current_company in

companies_controller.rb

before_action :set_company, only: [:show, :edit, :update, :destroy, :company_home]

def company_home
  current_company = @company
  respond_with(@company)
end

application_controller.rb

def current_company=(company)
  session[:current_company] = company.id
  puts "The current_company has been assigned"
  puts params.inspect
end

def current_company
  @company = Company.find_by_id(session[:current_company])
  puts "The current_company helper has been called"
  puts @company
  puts params.inspect
end

Am I doing something wrong?

Edit 2

I have no idea why this isn't working. After the above edits, it appears as though the session[:company_id] is not being assigned so the current_company helper method is returning nil. I've tried printing the session paramaters puts session.inspect and can't find any company_id information. Anyone any idea why it isn't assigning the value?

Edit 3

Can't for the life of me figure out what's going wrong. I've tried multiple things including moving the current_company = @company into the set_company method in companies_controller.rb which now looks like this:

def company_home
  puts "Test the current company"
  puts "#{@company.id} #{@company.name}"
  puts params.inspect
end

 private
  def set_company
    @company = Company.find_by_id(params[:id])
    if @company.nil?||current_user.organisation_id != @company.organisation.id
    flash[:alert] = "Stop poking around you nosey parker"
    redirect_to root_path
    else
    current_company = @company
    end      
  end

The company_home method is being given a company object (I can see this in the console output below) but the current_company assignment is just not happening. Here's the console output for reference

Started GET "/company_home/1" for 80.55.210.105 at 2014-12-19 10:26:49 +0000                                                                                                      
Processing by CompaniesController#company_home as HTML                                                                                                                            
  Parameters: {"authenticity_token"=>"gfdhjfgjhoFFHGHGFHJGhjkdgkhjgdjhHGLKJGJHpDQs6yNjONwSyTrdgjhgdjgjf=", "id"=>"1"}                                                                                   
  User Load (0.5ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = 6  ORDER BY "users"."id" ASC LIMIT 1                                                                    
  Company Load (0.3ms)  SELECT  "companies".* FROM "companies"  WHERE "companies"."id" = 1 LIMIT 1                                                                                
  Organisation Load (0.3ms)  SELECT  "organisations".* FROM "organisations"  WHERE "organisations"."id" = $1 LIMIT 1  [["id", 6]]                                                 
Test the current company                                                                                                                                                          
1 Cine                                                                                                                                                                            
{"_method"=>"get", "authenticity_token"=>"gfdhjfgjhoFFHGHGFHJGhjkdgkhjgdjhHGLKJGJHpDQs6yNjONwSyTrdgjhgdjgjf=", "controller"=>"companies", "action"=>"company_home", "id"=>"1"}                          
  Rendered companies/company_home.html.erb within layouts/application (0.1ms)                                                                                                     
  Company Load (0.6ms)  SELECT  "companies".* FROM "companies"  WHERE "companies"."id" IS NULL LIMIT 1                                                                            
The current_company helper has been called                                                                                                                                        

{"_method"=>"get", "authenticity_token"=>"gfdhjfgjhoFFHGHGFHJGhjkdgkhjgdjhHGLKJGJHpDQs6yNjONwSyTrdgjhgdjgjf=", "controller"=>"companies", "action"=>"company_home", "id"=>"1"}                          
  CACHE (0.0ms)  SELECT  "organisations".* FROM "organisations"  WHERE "organisations"."id" = $1 LIMIT 1  [["id", 6]]                                                             
Completed 200 OK in 280ms (Views: 274.0ms | ActiveRecord: 1.7ms)

As per above, under the line The current_company helper has been called, there's a blank line where puts @company should be outputting something. This means the current_company method is returning nothing.

Also, in the company_home method in the companies_controller, if I change puts "#{@company.id} #{@company.name}" to puts "#{current_company.id} #{current_company.name}" an error gets thrown.

Has anyone any idea why the def current_company=(company) isn't assigning a session parameter? Thanks

Final Edit

I've no idea why, but it appears the problem related to this:

def current_company=(company)
  session[:current_company] = company.id
  puts "The current_company has been assigned"
  puts params.inspect
end

It looks as though this never gets called. I don't understand why as I've never used something like this before.

I'll put my fix in an answer.

9
  • Yes, you are summoning session[:id] when you really need to access session[:company_id] Commented Dec 18, 2014 at 22:23
  • Changed it to 'session[:company_id]' but still not working Commented Dec 18, 2014 at 22:27
  • Is there a rails_root/config/initializers/session_store.rb? If so, is there any line uncommented? Commented Dec 18, 2014 at 22:31
  • Yes the commented line is '# Be sure to restart your server when you modify this file.'. Am using Devise. Would that make any difference? Commented Dec 18, 2014 at 22:34
  • Ok, I've got it... If it is as you have it here, remove spaces around = in this line: current_company = @company and make it current_company=@company and see if it works Commented Dec 18, 2014 at 22:44

2 Answers 2

6

Ok, you need to do two things.

First thing, you need to assign your company.id to a session variable

def current_company=(company)
    session[:company_id]=company.id
end

Second, your helper method for current_company will be as follows:

def current_company
    Company.find_by_id(session[:company_id])
end

This can be nil if there is no session[:company_id] or if it corresponds to no company. That's ok...

Next, it is quite unlikely to get it working without an id, if you use /companies both for your index and your show actions.

Now, for your first task. Setting the variable:

controller:companies_controller.rb

def show
    # assuming you have a before_action, something like set_company, no need to redo it
    current_company=@company # this will set the session variable
end

If you want your navbar to lead to your current_company, you will need to write:

<% unless current_company.nil? %>
    <li><%= link_to "Company", current_company, :method => :get %></li>
<% end %>

I don't know what you want to do if there is no current company, so I just leave it out.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks but I still can't get working. I'll edit my original post
@AlD In Rails Tutorial Michael Hartl used a similar technique to define current_user, check this out: github.com/mhartl/sample_app_4_0_upgrade/blob/master/app/…
Just noticed your post D-side. I'll have a look at this thanks
0

Instead of using a helper method to assign a value or search for a company, I've assigned a session variable in the set_company method in companies_controller.rb. This can then be accessed around the application

companies_controller.rb

 private
    def set_company
       @company = Company.find_by_id(params[:id])

       if @company.nil?||current_user.organisation_id != @company.organisation.id
          redirect_to root_path
       else
          session[:current_company] = @company
          current_company = @company
       end      
    end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.