fire-model - REST wrapper for Firebase.

Install gem

gem install fire-model

Click here to create a free Firebase account if you don’t have one.

Setup Firebase. (If you are using Rails create a file Rails.root/config/initializers/fire_model.rb and put next line there).

require 'fire-model'
Fire.setup(firebase_path: 'https://<your subdomain here>.firebaseio.com')

Declare your Model

class LibraryBook < Fire::Model
  has_path_keys(:library, :floor, :row_number, :shelf)
end

Use query syntax

LibraryBook.create(library: 'Shevchenko', floor: 1, row_number: 1, shelf: 10, 
  name: 'Kobzar', author: 'T.G. Shevchenko')
LibraryBook.create(library: 'Shevchenko', floor: 1, row_number: 1, shelf: 15, 
  name: 'Eneida', author: 'I. Kotlyrevskiy')
LibraryBook.create(library: 'Shevchenko', floor: 2, row_number: 15, shelf: 115, 
  name: 'Lord Of The Rings', author: ' J.R.R. Tolkien')
LibraryBook.create(library: 'Skovoroda', floor: 1, row_number: 25, shelf: 34, 
  name: 'Harry Potter', author: 'J.K. Rowling')
LibraryBook.create(library: 'Skovoroda', floor: 2, row_number: 12, shelf: 15, 
  name: 'Hobbit', author: ' J.R.R. Tolkien')

LibraryBook.all.map(&:name)
=> [ 'Kobzar', 'Eneida', 'Lord Of The Rings', 'Harry Potter', 'Hobbit' ]

# Query by library
LibraryBook.query(library: 'Shevchenko').map(&:name)
=> [ 'Kobzar', 'Eneida', 'Lord Of The Rings' ]
LibraryBook.query(library: 'Skovoroda').map(&:name)
=> [ 'Harry Potter', 'Hobbit' ]

# Query by library, floor
LibraryBook.query(library: 'Shevchenko', floor: 1).map(&:name)
=> [ 'Kobzar', 'Eneida' ]

# Query by library, floor, row
LibraryBook.query(library: 'Shevchenko', floor: 1, row_number: 1).map(&:name)
=> [ 'Kobzar', 'Eneida' ]

# Query by shelf
LibraryBook.query(shelf: 15).map(&:name)
=> [ 'Eneida', 'Hobbit' ]

# Query by author
LibraryBook.query(author: ' J.R.R. Tolkien').map(&:name) 
=> [ 'Lord Of The Rings', 'Hobbit' ]

# Query by math condition
LibraryBook.query{|m| m.row_number % 5 == 0  }.map(&:name)
=> [ 'Lord Of The Rings', 'Harry Potter' ]

Play with CRUD

class Point < Fire::Model
  has_path_keys(:x, :y)
end

p1 = Point.create(x: 1, y: 1, value: 1)
p2 = Point.create(x: 1, y: 2, value: 2)
p3 = Point.create(x: 2, y: 1, value: 3)
p4 = Point.create(x: 1, y: 1, value: 4)

Point.all.map(&:value)
=> [ 1, 2, 3, 4 ]

p1.value = 5
p1.path_changed?
=> false

p1.save

reloaded_point = Point.take(x: p2.x, y: p2.y, id: p2.id)
reloaded_point.value = 6

reloaded_point.path_changed?
=> false

reloaded_point.save

p1.delete

Point.all.map(&:value)
=> [ 6, 3, 4]

p3.x = 4
p3.path_changed?
=> true

p3.save

Point.all.map(&:value)
=> [ 6, 3, 4]

Create Nested Models

class Organization < Fire::Model
  set_id_key(:name)
  has_path_keys :country, :state
end

class Employee < Fire::NestedModel
  nested_in Organization, folder: 'employees'
  has_path_keys :department
end

google = Organization.create(name: 'Google', country: 'USA', state: 'CA')
apple = Organization.create(name: 'Apple', country: 'USA', state: 'CA')

larry = Employee.create(name: 'Google', country: 'USA', state: 'CA',
  department: 'HQ', full_name: 'Larry Page', position: 'CEO')
  
employee = Organization.query(name: 'Google').first.nested_employees.first
larry == employee
=> true

employee.department = 'Research'
employee.save
=> true

google.reload
  
tim = apple.add_to_employees(
  full_name: 'Tim Cook',
  position: 'CEO',
  department: 'HQ'
)

Fire.tree
=> {'Organization'=>
     {'usa'=>
          {'ca'=>
               {'apple'=>
                    {'country'=>'USA',
                     'employees'=>
                         {'hq'=>
                              {'h543ka'=>
                                   {'department'=>'HQ',
                                    'full_name'=>'Tim Cook',
                                    'id'=>'h543ka',
                                    'position'=>'CEO'}}},
                     'name'=>'Apple',
                     'state'=>'CA'},
                'google'=>
                    {'country'=>'USA',
                     'employees'=>
                         {'research'=>
                              {'d23h1a'=>
                                   {'department'=>'Research',
                                    'full_name'=>'Larry Page',
                                    'id'=>'d23h1a',
                                    'position'=>'CEO'}}},
                     'name'=>'Google',
                     'state'=>'CA'}}}}}

Single Nested Models

class Car < Fire::Model
  has_path_keys :manufacturer, :model, :car_class
end

class Engine < Fire::SingleNestedModel
  nested_in Car
end

scirocco = Car.create(manufacturer: 'Volkswagen', model: 'Scirocco', car_class: 'Sport compact')
scirocco.add_to_engine(code: 'I4 turbo', power: '122 PS')

car = Car.create(manufacturer: 'Zaporozhets', model: 'ZAZ-965', car_class: 'Mini', 
  engine: { code: 'MeMZ-966' })

zaporozhets = Car.take(manufacturer: 'Zaporozhets', model: 'ZAZ-965', car_class: 'Mini', id: car.id)
zaporozhets.nested_engine.code
=> 'MeMZ-966'

Fire.tree
=> {
  'Car'=>
    {'volkswagen'=>
         {'scirocco'=>
              {'sport-compact'=>
                   {'adqa21'=>
                        {'car_class'=>'Sport compact',
                         'engine'=>{'code'=>'I4 turbo', 'power'=>'122 PS'},
                         'id'=>'adqa21',
                         'manufacturer'=>'Volkswagen',
                         'model'=>'Scirocco'}}}},
     'zaporozhets'=>
         {'zaz-965'=>
              {'mini'=>
                   {'23rtfw'=>
                        {'car_class'=>'Mini',
                         'engine'=>{'code'=>'MeMZ-966'},
                         'id'=>'23rtfw',
                         'manufacturer'=>'Zaporozhets',
                         'model'=>'ZAZ-965'}}}}}})

zap2 = Car.take(manufacturer: 'Zaporozhets', model: 'ZAZ-965', car_class: 'Mini', id: car.id)
zap2.nested_engine.update(code: 'MeMZ-555')
zaporozhets.nested_engine.reload.code
=> 'MeMZ-555'

Nested Models with Parent`s values

class House < Fire::Model
  set_id_key(:house_number)
  has_path_keys :country, :city, :street
end

class Room < Fire::NestedModel
  set_id_key(:number)
  nested_in House, parent_values: true
  has_path_keys :floor
end

house = House.create(country: 'Ukraine', city: 'Kyiv', 
  street: 'Shevchenko Ave.', house_number: '53101')
  
house.add_to_rooms(floor: 200, number: '1A')
house.add_to_rooms(floor: 150, number: '2A')


rooms = house.reload.nested_rooms
rooms.map(&:number)
=> [ '1A', '2A' ]

Fire.tree
=>  {'House'=>
      {'ukraine'=>
           {'kyiv'=>
                {'shevchenko-ave'=>
                     {'53101'=>
                          {'city'=>'Kyiv',
                           'country'=>'Ukraine',
                           'house_number'=>'53101',
                           'rooms'=>
                               {'150_'=>
                                    {'2a'=>
                                         {'city'=>'Kyiv',
                                          'country'=>'Ukraine',
                                          'floor'=>150,
                                          'number'=>'2A',
                                          'house_number'=>'53101',
                                          'street'=>'Shevchenko Ave.'}},
                                '200_'=>
                                    {'1a'=>
                                         {'city'=>'Kyiv',
                                          'country'=>'Ukraine',
                                          'floor'=>200,
                                          'number'=>'1A',
                                          'house_number'=>'53101',
                                          'street'=>'Shevchenko Ave.'}}},
                           'street'=>'Shevchenko Ave.'}}}}}})

Examples

Check this example to see how fire-model integrates in a Rails app.

Contributing to fire-model

Copyright

Copyright © 2015 Vitaly Tarasenko. See LICENSE.txt for further details.