Search code examples
rubysinatrasequel

How can I get this ruby code with sequel to work in sinatra?


I am trying to only allow a person to see the page if their name is in the database. I figured the best way to go about it was to loop through all of the entries and check if it matches, if it does then display it and stop looping. I keep getting a blank page, any help?

get '/' do
  user  = "john"
  num = DB[:users].all

  for person in num  do
    if person[:name].to_s == user then
      File.read('index.html')
      break
    else 
      "you're not authorized"
    end
  end

end

If I were to remove the line that says break within the if statement, I get this error:

  NoMethodError at /
  undefined method `bytesize' for #<Hash:0x007fcf60970a68>
  file: utils.rb location: bytesize line: 369

Solution

  • The problem is that a for loop evaluates to nil (unless you break and supply a value to break), so your block is returning nil, so there's nothing to render.

    But the real problem is that for is the wrong solution here. What you're trying to do is check if the Array DB[:users].all contains a Hash whose :name member equals user. You can use a loop for that, but in addition to for being rare in idiomatic Ruby code (Enumerable#each is preferred) it makes the intent of your code harder to understand. Instead, you could use Enumerable#find (the Array class includes the methods in the Enumerable module) like so:

    get '/' do
      username = "john"
      users = DB[:users].all
    
      matching_user = users.find do |user|
        user[:name] == user
      end
    
      if matching_user
        return File.read('index.html')
      end
    
      "you're not authorized"
    end
    

    ...but since you don't actually care about the matching user—you only care if a matching user exists—it would be clearer to use Enumerable#any?, which just returns true or false:

    get '/' do
      username = "john"
      users = DB[:users].all
    
      if users.any? {|user| user[:name] == user }
        return File.read('index.html')
      end
    
      "you're not authorized"
    end
    

    Edit: As @user846250 points out, it would be better to let the database do the work of checking if any matching users exist. Something like this:

    get '/' do
      username = "john"
    
      if DB[:users].where(:name => username).empty?
        return "you're not authorized"
      end
    
      File.read('index.html')
    end
    

    This is preferable because instead of loading all of the records from the database into Ruby (which is what DB[:users].all will do)—when you don't actually care about the data in any of them—Sequel will just ask the database if there are any matching records and then return true or false.