Thursday, November 27, 2014

Devise login with membership id

I am currently working on another small project, where Devise is used for authentication. The project requires that users log in with a membership id instead of an email and a password (these are default Devise settings). The project is set up in such a way that an admin creates users using their membership id, and then the users log in with the membership id. The users can't delete their account; only an admin can.

Based on Devise documentation and other research, it appeared that several things needed to be done. First, one needs to create a membership id in the User table, and to add this parameter to the list of permitted parameters. Second, the log in form needs to be modified so that it includes the membership id only.

However, adding the membership id to the list of permitted parameters was only a partial solution. It would allow me to register the user using the membership id but when I would try to log the user in, I would get an authorization error.

Since Devise uses Warden for authorization and the default settings include email and password, the solution was to add another Warden strategy, so that the membership id would be recognized as a legitimate choice.

In initializers directory I created a file named membership_strategy.rb:

require 'devise/strategies/authenticatable'

module Devise
  module Strategies
   class Membershipid < Authenticatable

     def valid?
       true
     end

     def authenticate!
       if !params[:user].nil?
         auth_params = {}
         auth_params[:membershipid] = params[:user][:membershipid]
         resource = mapping.to.find_for_authentication(auth_params)

         if validate(resource){ resource.find_for_database_authentication(auth_params) }
            success!(resource)
         else
            fail!(:invalid)
         end
       end
     end
   end
  end
end
Warden::Strategies.add(:membershipid, Devise::Strategies::Membershipid) 

In initializers/devise.rb the following line needs to be appended to the beginning:

config.warden do |manager|
   manager.default_strategies(:scope => :user).unshift :membershipid
end

Friday, November 21, 2014

First hackathon

It's been a little while since I wrote the last post, but some interesting events have happened. Last weekend I attended my first hackathon - DevelopHer, organized by LinkedIn. It was a 24-hour event for women developers, and it was a great experience. And big thanks to organizers who provided the space and opportunity for people to participate.

Our team worked on creating an app on farmers' markets and fruits and vegetables that would be available from a market. The idea was to allow a user to search for nearest farmer markets by zipcode, and to browse the goodies that the markets would offer. Other options would include the recipes of foods that could be made from fruits and vegetables. The app was built with Python and Django framework.

We didn't finish the app but our team plans on working on it. I expect the results to be awesome.

I did learn a lot from the hackathon. It was great to work with Django, since I've never used it before. I found that Rails experience helped me to catch on Django quickly. I have new friends and a team to work with on future projects. Certainly looking forward to more hackathons.




Monday, November 10, 2014

Yet another Chess

I really hope this is the last post on chess game! Once I was done with writing a version in Ruby, I have translated the major functionality into a Javascript game. The Ruby version was very hard to play since it is terminal-based; however, the Javascript version certainly makes it more visual.

It can be played here, though Github. The game currently supports determining checks only. Mate is being determined in some situations but not all. Still room to improve but I need to move onto other projects.

Wednesday, November 5, 2014

More on Chess

I've been working on my chess game (see previous post) for a while by now. Primarily because once I had the main logic in, I did quite a bit of refactoring of the design over and over. While it can be improved further, my current design is as follows.

There are nine classes: Game, Board, Piece, and 6 Piece subclasses (Pawn, King etc). There is also a module called Converter that assists in converting x and y coordinates of the Board into 1D array, and vice versa.

The Piece class has the majority of methods that subclasses inherit from. Its basic structure is as follows:

class Piece
    include Converter
    attr_accessor :id, :x, :y

    def initialize(color=:white,x=0,y=0)
    end

    def move_to(x,y)
    end

    # determines what cells a piece can theoretically go to
    # in parent class, this method checks the board boundaries 
    def can_piece_move?(to_x, to_y)
    end

    # determines whether a piece can move to a cell (e.g., if it is empty).
    # Also "captures" an enemy piece
    # if the destination cell is occupied by one.
    def valid_move?(board, to_x, to_y)
    end
end

All Piece subclasses inherit these methods and override them as needed. Thus, each Piece subclass naturally implements its own version of can_piece_move?(to_x, to_y). All Piece subclasses except for Pawn use the method valid_move?(board, to_x, to_y) as defined in the parent class. However, Pawn has its own implementation of the valid_move? method because Pawn can only move in one direction vertically and can only capture in one direction diagonally.

Additionally, the Pawn class implements a special method that allows to count how many times the Pawn was moved (as a reminder, a Pawn can be moved 1 or 2 steps at a first move, but only 1 step afterwards). The King class has a special method as well - this method loops through surrounding cells and returns an array of cells where the King can move to. This method is used in determining whether the King is in check.

The Board class is shown below. Instead of placing Pieces directly into the Board matrix, I have chosen to create a collection of pieces, where each Piece has an id calculated on the basis of x and y coordinates of the Board. All positions are thus calculated on the basis of this id. Accordingly, it is easy to find a Piece in a collection by its id or to remove a Piece from the collection once it's been captured.

class Board
    include Converter
    attr_accessor :board, :piece_collection, :destination

    def initialize
        @board = Array.new (Converter.rows) { |i| Array.new(Converter.cols) { |j| nil } }
        @piece_collection = []
        @king_collection = []
    end
   
    # places pieces into corresponding collections
    def setup_pieces
    end

    def remove_piece_from_collection(piece)
    end

    def find_piece_in_collection(pid)
    end
   
    # determines whether the king has any moves left
    def legal_moves_left?(king)
    end

    # determines if the king is in immediate danger
    def threatening_piece(king)
    end
   
    # determines if the path is free/blocked 
    def is_it_blocked?(from_x, from_y, to_x, to_y)
    end

    def display
    end
end

Finally, the Game class determines the sequence of events and checks for a winner. The sequence of events is quite straightforward: a player inputs an id of the Piece she wants to move, and an id of the location where to move the Piece to. If the move is valid, the Game updates x and y coordinates of the involved Pieces and calls a method to determine whether there is a winner. The winner method looks as follows:

def determine_winners(board)
    board.king_collection.each do |king|
       board.destination = king
       threat = board.threatening_piece(king)
       legal_moves = board.legal_moves_left?(king)

       if legal_moves == true && !threat.nil?
          puts "WINNING: #{threat.full_description} Check!"
          return true
       elsif legal_moves == false && !threat.nil?
          puts "WINNING: #{threat.full_description} Check & Mate!"
          @game = false
          return true
       elsif legal_moves == false && threat.nil?
          puts "WINNING: #{player_turn.upcase} StaleMate!"
          @game = false
          return true
       end
    end
    false
end

The full code is available at my Github. I still wonder how it is possible to improve the design. It appears that the Piece and Board are heavily dependent on each other and the same arguments (board, to_x, to_y) are constantly being passed around. As they said in BerkeleyX SaaS Engineering course, if a group of arguments keeps traveling around, they may have to be extracted into a separate class. I guess as I learn more about OO design (and Sandi Metz's book "Practical Object Oriented Design in Ruby" has been already a great help), I will find myself re-writing the game again.