Create a new repository on the command line
touch README.md
git init git add README.md git commit -m “first commit” git remote add origin github.com/ycchen/apg-inventory.git git push -u origin master Push an existing repository from the command line
git remote add origin github.com/ycchen/apg-inventory.git git push -u origin master
-
create arl-inventory application
$ rails new arl-inventory
-
added devise gem in Gemfile
-
install devise gem
$ rails g devise:install
-
create user model
$ rails g devise User
-
added :display_name field, and enable all of additional fields and indexes
$ rails db:migrate
-
Updated appliction.html.erb with layout
-
created flashes_helper in apphelpersapplication_helper.rb
def flashes_helper
results = [] flashes = [:alert, :error, :info, :notice, :success] flashes.each do |name, msg| hidden = "hide" if flash[name].blank? results << content_tag(:div, content_tag(:p, flash[name]), class: "alert alter-#{name} #{hidden} alert-block").html_safe end results.join("").html_safe
end
-
created title and show_title? method in apphelpershome_helper.rb
def title(page_title, show_title=true)
content_for(:title){h(page_title.to_s)} @show_title = show_title
end
def show_title?
@show_title
end
-
add twitter bootstrap library to application.css and application.js
-
generated home controller
$ rails g controller home index
-
update configroutes.rb point root to home#index
-
generated inventory model
$ rails g scaffold inventory stockenumber:string name:string description:text barcode:string purchase_date:date
$ rails g scaffold inventory_status name:string
$ rails g scaffold location name:string address:string latitude:float longitude:float
$ rails g scaffold inventory_record user:references inventory:references inventory_status:references location:references latitude:string longitude:string
-
Added relationship between all models and validations
-
models/user.rb
validates :email, :presence => true validates :password, :presence => true validates :password_confirmation, :presence => true validates :display_name, :presence => true
has_many :inventory_records has_many :inventories, :through => :inventory_records
-
models/inventory.rb validates :barcode, :presence => true validates :description, :presence => true validates :name, :presence => true validates :purchase_date, :presence => true
-
models/inventory_status.rb
validates :name, :presence => true has_many :inventory_records
-
models/location.rb
validates :name, :presence => true validates :latitude, :presence => true validates :longitude, :presence => true
has_many :inventory_records
-
models/inventory_record.rb
belongs_to :user belongs_to :inventory belongs_to :inventory_status belongs_to :location
-
Added avatar method
def avatar
Gravatar.new(self.email).image_url
end
-
generated pre-populate data set in dbseed.rb
-
added RoutingError handler at the end of routes.rb
-
configroutes.rb
match ‘*path(.:format)’, :to=> ‘application#routing_error’
-
controllerapplication_controller.rb
def routing_error
render_not_found
end
def render_not_found
flash[:notice] = 'The object you tried to access does not exist!' redirect_to root_path
end
-
added ActiveRecord::RecordNotFound handler
-
controllerapplication_controller.rb
rescue_from ActiveRecord::RecordNotFound, :with => :render_not_found
-
generated User view for customization
$ rails g devise:views devise
-
Added javascript to handle slidUp alert div in application.js
$(function(){
$('.alert').delay(5000).slideUp('slow');
});
-
Added validation for InventoryRecord model and added more field in attr_accessible
/*
attr_accessible validates :user_id, :presence => true validates :inventory_id, :presence => true validates :inventory_status_id , :presence => true validates :location_id, :presence => true
*/
-
Added “rolify”, “cancan” gems to handle user roles
-
modified Gemfile
-
gem ‘rolify’ # role management
-
gem ‘cancan’ # authroization
-
Create the Ability class from Cancan
$ rails generate cancan:ability
-
Create the Role class from rolify
$ rails generate rolify:role
-
Run migrations
$ rake db:migrate
Added “cancan” gem to handle user roles: cancan expect a curent_user method to exist in the controller, so we need to setup some authentication (such as Devise)
/*********** this is replaced by using rolify gem
-
Added typical users HABTM (Has and belongs to many) roles relationship
$ rails g scaffold role name:string
$ rake db:migrate
$ rails g scaffold roles_users role:references user:references
$ rake db:migrate
-
Added relationship between user and role model
-
user model
has_many :roles_users has_many :roles, :through => :roles_users
-
role model
has_many :roles_users has_many :users, :through => :roles_users
*****************/
************** READ THIS BEFORE ENABLE config.use_dynamic_shortcuts
BY ENABLE config.use_dynamic_shortcuts will cause db:migrate raise exception of “could not find table roles”, you will need to run db:migrate first then uncomment dynamic_shortcuts each time you want to initial the application
danielboggs.com/articles/rails-authentication-and-user-management-continued
**************
-
enable dynamic shortcuts for user class (user.is_admin? like methods), uncomment “config.use_dynamic_shortcuts
" the line in 'config/initializers/rolify.rb'
-
added gmaps4rails gem to Gemfile for Google Maps for Rails
github.com/apneadiving/Google-Maps-for-Rails
learningpoint2.wordpress.com/2012/12/19/google-map-in-rails/
gem ‘gmaps4rails’
-
copy the assets to your app
$ rails g gmaps4rails:install
-
updated modelslocation.rb
acts_as_gmappable :latitude => ‘latitude’, :longitude => ‘longitude’, :process_geocoding => :geocode?, :address => ‘address’, :normalized_address => ‘address’,:msg => “Sorry, not even Google could figure out where that is”
def geocode? (!address.blank? && (latitude.blank? || longitude.blank?)) || address_changed? end def gmaps4rails_address address end def gmaps4rails_infowindow "<h4>#{name}</h4>" << "<h4>#{address}</h4>" end
-
Added @json = Location.all_to_gmaps4rails in controllers/location.rb
-
Added following in layoutapplication.html.erb at the footer area
<%= yield :scripts %>
-
Added <%= gmaps4rails(@json) %> in views/locations/index.html.erb
-
Added :unregistered scope in Inventory model modlesinventory.rb
scope :unregistered, where(“id NOT IN (select inventory_id from inventory_records where inventory_records.inventory_id = inventories.id)”)
-
modified viewinventory_form.html.erb to handle different params to user Inventory.all or Inventory.unregistered
-
Added dashboard controller
$ rails g controller dashboards show
guides.rubyonrails.org/debugging_rails_applications.html
-
debug
<%= debug @post %>
-
to_yaml
<%= simple_format @post.to_yaml %>
-
inspect
<%= @location.inspect %>
-
Rails.logger.debug()
-
using irb console to test the condition
t = “hello” c = “world” # if (t == c )
desc else asc
v = (t == c) ? “desc” : “asc” # v = “asc”
-
Generated following models
$ rails g scaffold category name:string description:text
$ rails g scaffold brand name:string
$ rails g scaffold group name:string description:text
-
Generate user controller
$ rails g controller Users index
-
Added isAdmin? in controllerapplication_controller.rb
def isAdmin? unless current_user && current_user.admin? flash[:notice]= "You are not authorize to access this page!" redirect_to root_path end end
Add before_filter : isadmin? for all models controllers
-
Added access restriction for controller - Added before_filter on all controllers that restrict only admin can get to it
before_filter :authenticate_user! before_filter :isAdmin?
-
Added pagination for all models using Kaminari gem
Kaminari configuration options
$ rails g kaminari:config # generated config/initializers/kaminari_confifg.rb file
If you want to change default “per_page” value, you can do it on each model
# Kaminari will crashed for ruby 1.9.3-p362, but works fine on ruby 1.9.3-p392
class User < ActiveRecord::Base
paginates_per 10
end
railscasts.com/episodes/254-pagination-with-kaminari?view=asciicast
-
Added inventory_categories model
$ rails g model inventory_category inventory:references category:references
$ rake db:migrate
Added relationship between category, inventory, and inventory_category models
# category model has_many :inventory_categorys has_many :inventories, :through => :inventory_categorys
# inventory model has_many :inventory_categorys has_many :categories, :though => :inventory_categorys
# inventory_category model belongs_to :inventory belongs_to :category
Added following method to modelsinventory.rb, and added :category_ids in attr_accessible
def category_ids=(params)
self.categories =[] params.each do |id| unless id.to_s.empty? category = Category.find(id) categories << category end save end
end
-
Updated seed.rb file for pre-populate inventory data with assigned categories.
Multiple select box #1
<%= f.collection_select(:inventory_id, Inventory.unregistered, :id, :name, {include_blank: true}, {multiple: true}) %>
Multiple select box #2
<%= f.select(:inventory_id, Inventory.unregistered.collect{|x| [x.name, x.id]}, {}, {:multiple => true, :size => 10}) %>
Multiple select box #3
<%= select_tag(“inventory_record[]”, options_from_collection_for_select(Inventory.unregistered,“id”, “name”), :multiple => true) %>
Checkboxes
<% Inventory.unregistered.each do |item| %>
<%= check_box_tag "inventory_record[inventory_id][]", item.id %> <%= lable_tag dom_id(ite), item.name %>
<% end %>
-
Generate Unique Random string in ruby
$ require ‘securerandom’ $ SecureRandom.hex(13) $ SecureRandom.hex(15) $ SecureRandom.hex(32)
api_string = Array.new(32){rand(36).to_s(36)}.join
ActiveSupport::SecureRandom.hex(32)
-
Added handreciept model/controller/view
$ rails g scaffold hand_reciept reciept:string user:references
/*
-
Added handreciept_detail model/controller/view
$ rails g scaffold handreciept_detail hand_reciept:references inventory:references starts_at:datetime ends_at:datetime out_at:datetime in_at:datetime out_assistant_id:integer in_assistant_id:integer request_note:text approver_id:integer approval_note:text location:references inventory_status:references */
apg
-
Generated models
$ rails g scaffold component_model brand:references name:string description:text training_required:boolean autocomplete:string
$ rails g scaffold budget name:string number:string starts_at:date ends_at:date
$ rails g scaffold kit location:references budget:references tombstoned:boolean checkoutable:boolean cost:decimal insured:boolean
$ rails g scaffold component kit:references component_model:references asset_tag:string serial_number:string barcode:string
regenerated schema.rb
$ rake db:schema:dump
-
Added validations for budget model
custom method validation for date range
validate :starts_at_must_be_before_ends_at, :fields =>[:starts_at, :ends_at]
def starts_at_must_be_before_ends_at
errors.add(:starts_at, "must be before ends_at") unless starts_at < ends_at
end
-
Added nested_form gem
$ rails g nested_form:install
change_column :products, :price, :decimal, :precision => 6, :scale => 2
-
Added draper gem for model/view decorators (presenters)
$ rails g resource Article $ rails g decorator kit
railscasts.com/episodes/17-habtm-checkboxes?view=asciicast
-
product[]
to check if the product[] is pass in the update method do this This will set the params[:category_ids][] to an empty [] array, if the params[:category_ids][] does not pass in
def update
params[:product][:category_ids][] ||=[]
end
params[:category_ids][] will only generate from has_and_belongs_to_many, if we set up as has_many :through, we will have to generate category_ids manually.
-
Generated hand_reciepts_inventories model
$ rails g scaffold hand_reciept_details hand_reciept:references inventory:references inventory_status:references location:references user:references
$ rake db:migrate
Nested_form example
stackoverflow.com/questions/9649063/autocomplete-using-nested-form-on-has-many-through-relationship
stackoverflow.com/questions/13506735/rails-has-many-through-nested-form
38. $ rails g scaffold physician name:string $ rails g scaffold patient name:string $ rails g scaffold appointment physician:references patient:references appt_date:datetime note:text
added nested_form for hand reciepts model
-
Generated migration script to add hand_reciept_id to Inventory Record model
$ rails g migration add_hand_reciept_id_to_inventory_records hand_reciept_id:integer
-
Generated migration script to add appt_time and modify appt_date to date
$ rails g migration add_appt_time_to_appointments appt_time:time $ rails g migration change_appt_date_to_appointments appt_date:date
-
To concatenate 2 files in select box
<%= f.select(:hand_reciept_id, HandReciept.includes(:user).all.collect{|hr| [(hr.user.display_name + “ - ” + hr.reciept), hr.id]}) %>
<%= f.select(:hand_reciept_id, HandReciept.includes(:user).all.collect{|hr| [(hr.user.display_name+ “ - ” + hr.reciept), hr.id]}, {:include_blank => ‘Select Hand Reciept’}) %>
<%= f.select(:hand_reciept_id, HandReciept.includes(:user).all.map{ |c| [(c.user.display_name + “-” + c.reciept), c.id] }, :include_blank => “- Choose Name -”) %>
-
How to reference a scope in other models
defined a scope in user model called “no_hand_reciept_yet” This is out you reference to “no_hand_reciept_yet” in viewshand_reciepts_form.html.erb
<%= f.select(:user_id, User.no_hand_reciept_yet.map{|c|})%>
-
Added sort option on inventory records page.
index: appcontrollersinventory_records_controller.rb params ||= “created_at desc”
-
Added sortable helper method in apphelpersapplication_helper.rb
def sortable(column, title = nil) title ||= column.titleize direction = (column == params[:sort] && params[:direction] == "asc") ? "desc" : "asc" link_to title, :sort => column, :direction => direction end <%= link_to "User", :sort =>"users.display_name %> Replace with <%= sortable("users.display_name","User") %> app\controllers\inventory_records_controller.rb def index @inventory_records = InventoryRecord.includes([:user, :inventory,:location, :inventory_status]).order(params[:sort] + ' ' + params[:direction]) end
# Re-factor the sortable method
app\controllers\inventory_records_controller.rb helper_method :sort_column, :sort_direction def index @inventory_records = InventoryRecord.includes([:user, :inventory,:location, :inventory_status]).order(sort_column + ' ' + sort_direction) end
# In order to access those 2 method thru the view, we need to enable them to be accessable by the view, we need to call the helper_method to make them avaliable by view
private def sort_column params[:sort] ||= "created_at" end def sort_direction params[:direction] ||= "desc" end app\helpers\application_helper.rb def sortable(column, title = nil) title ||= column.titleize direction = (column == sort_column && sort_direction =="asc") ? "desc" : "asc" link_to title.titleize, :sort => column, :direction => direction end
-
Make rails console just output the query only
# add nil at the end of each query commands/statements $ users = User.all; nil
# best output on rails console using awesome_print and hirb (hirb does not work with rails 3.2)
-
use Ruby constant “RUBY_PLATFORM” to find out which OS ruby is runnin gon
<%= RUBY_PLATFORM %> i386-mingw32, i686-linux
# add show_debug method to dump request scope variables in helpersapplication_helper.rb
def show_debug if Rails.env.development? request.env.each do |e| debug("#{e[0]} = #{e[1]}") end end end <% if Rails.env.development? %> <% request.env.each do |e| %> <%= debug(e[0].to_s + ' = ' + e[1].to_s) %> <% end %> <% end %>
-
committed for updated sortable method to ensure the arrow image shows up
-
restrict access for inventory controller on edit, update, and destroy, and allows users can view inventory list and inventory details, hidde edit option for non admin user
add to all view links where you want to have access control
<% if can? :manage, @inventory %>
<%= link_to %>
<% end %>
-
modified search method to add couple more fields to be search. Enable search form for all users.
modelsinventory_record.rb
def self.search(search)
end
-
committed - Modified search query, added can? on views