0

I have set @user_ctypes, but, when I access to it from a model, I get a Nil value. Why?

This is a TV Guide and an user (current_user) will set which are channels that it want to hide. For example: If the logged user doesn't have a satellite, he will have ctypes=['sat']. So any channels that is aired on satellite will be hidden to user. If user is not logged, current_user is nil.

I'd want to use "default_scope" because any query to DB should be take care of which channels the user wants to see.

ApplicationController

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

  before_filter :set_user_ctypes


  private

  def set_user_ctypes
    unless current_user.nil? 
      @user_ctypes = current_user.ctypes 
    else
      @user_ctypes =  Array.new
    end
  end

Model

 class Channel < ActiveRecord::Base
      has_many :programs, :dependent => :delete_all

       validates :name, :site, :ctype, :country, :presence => true


      default_scope {where.not(ctype: @user_ctypes)}

User (by Devise)

class User < ActiveRecord::Base
4
  • you can't access instance variables in a model... Commented Dec 4, 2013 at 22:28
  • Is there any relationship between channels and users? Commented Dec 5, 2013 at 21:05
  • Instead of using unless/else, I'd suggest changing the code so you can use if/else. It will improve the readability of the code. Commented Dec 5, 2013 at 21:35
  • @JasdeepSingh No, no relationship Commented Dec 5, 2013 at 22:42

2 Answers 2

5

A controller (your ApplicationController in this case) and a model (Channel in this case) are different instances of different objects and therefore don't share instance variables, hence you can't use instance variables in a model.

In general, to pass in a variable into a scope you'd normally do something like this:

scope :name lambda{|user_ctypes| { where.not(ctype: user_ctypes) }

Here's the problem, this is a default scope, and so you can't really share an instance variable created in a controller with it, because otherwise it's a little like a global variable.

Consider having a look at this bit and see if there's a better way of doing it, I always find with Rails that if it's hard to do/not doable it's probably wrong. Maybe you could consider using a normal scope or moving your logic elsewhere.

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

4 Comments

Setting session[:user_ctypes] instead of @user_ctypes in ApplicationController should be better? Because I tried but I get undefined local variable or method `session' in Model default_scope {where.not(ctype: session[:user_ctypes])}
It won't work either - model objects don't have access to the session, that's only available in controllers, helpers and views.
@user1028100 eugen is right, it's the same thing again. Maybe give us some context, where is the scope used etc and see if we could help with refactoring it.
great thanks. So current_user.ctypes, is there a Ctype model? I think a habtm relationship between users and channels makes the most sense, and if this Ctype model is there, it could be modified slightly to do it. I'm guessing it isn't, but maybe we're lucky :) Ignoring that it doesn't actually work, I can see that what you've done is 'easier' but there's two db calls here, and it's just not scalable, there's probably features down the line which would be hampered by this. So yep, is Ctype a model or just an array in the user model?
-3

this happens because you have put as private the method where has been declared the @user_ctypes variable

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.