-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathROR Tricks from screencasts.txt
2530 lines (1933 loc) · 94 KB
/
ROR Tricks from screencasts.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1) To use controller methods into views ---> helper_method :action_name (Screencast - 20)
1.5) To include any helper file(helper module) in controller ---> helper :authentication (for authentication_helper.rb) (Screencast - 64)
If u want to use any helper method provided by rails then, u can use it by calling the method on ActionController::Base.helpers
def description
"This category has #{helpers.pluralize(products.count, 'product')}."
end
def helpers
ActionController::Base.helpers
end
However, some of the helper methods link link_to will not be accessible on models because they depend on request object but they can be accessed on controllers which has access to request object, by using @template variable. Ex
def create
@product = Product.new(params[:product])
if @product.save
flash[:notice] = "Successfully created #{@template.link_to('product', @product)}."
redirect_to products_url
else
render :action => 'new'
end
end
2) In the view, we can use pluralize method to display 1 or more items.
<%= pluralize project.tasks.size, 'task' %>
3) In :include --> name of the association should be used .It can also be chained
Task.find(:all, :include => [:projects, {:comments => :user}])
Task --> belongs_to :project, has_many :comments . Comment ---> belongs_to :user
4) Use CGI::escapeHTLM(...) in controller to reject html content
Use CGI.escape to embed a sentence or set of words containing spaces in a URL
url = "http://www.walmart.com/search/search-ng.do?search_constraint=0&ic=48_0&search_query=#{CGI.escape(product.name)}&Find.x=0&Find.y=0&Find=Find"
5) size method uses the counter cache feature of rails but length doesnot.
project.tasks.size --> uses counter cache
6) Use attr_accessible to prevent mass_assignment.
attr_accessible :name --> means only name can inputed using mass assignment (curl)
curl -d "user[name]=hacker&user[admin]=1" http://localhost:3000/Users/
curl -d "user[name]=hacker&user[admin]=1&user[comment_ids][]=1&user[comment_ids]=2" http://localhost:3000/users/create
7) >> a = (1..12).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
>> a.in_groups_of(4)
=> [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
>> a.in_groups_of(3)
=> [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
>> a.in_groups_of(5)
=> [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, nil, nil, nil]]
>> a.in_groups_of(5, false)
=> [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12]]
>> a.in_groups_of(5, 0)
=> [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 0, 0, 0]]
8) From cmd type
> ri strftime
Display the documentation (classes that have method strftime)
> ri Time.strftime
Shows description
9) http://localhost:3000/tasks/completed == http://localhost:3000/tasks;completed (In Edgerails only / works ; doesn't)
10) Creating a rails pluggin (Railscast 33): similar to gem creation
module StringifyTime
def stringify_time(*names)
names.each do |name|
define_method "#{name}_string" do
read_attribute(name).to_s(:db) unless read_attribute(name).nil?
end
define_method "#{name}_string=" do |time_str|
begin
write_attribute(name, Time.parse(time_str))
rescue ArgumentError
instance_variable_set("@#{name}_invalid", true)
end
end
define_method "#{name}_invalid?" do
instance_variable_get("@#{name}_invalid")
end
end
end
end
read_attribute & write_attribute are methods of active record
11) Use form_tag to make a generic form & form_form to update a database model attributes.
12)
<% form_tag projects_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search" %> === <input name="commit" type="Submit" value="Search" />
</p>
<% end %>
The above form submit the form with URL:
http://localhost:3000/projects?search=yard&commit=Search
yard :- searched project
So to remove commit=Search from the URL write
<%= submit_tag "Search", :name => nil %>
Then the URL becomes : http://localhost:3000/projects?search=yard
13) If you are using form_remote_for then instaed of submit_tag (if you have two submit buttons : Create & Preview) for a project, you should use submit_to_remote becoz form_remote_for serealizes the whole form and submits.
14) helper_method : capture(&block) --> returns content of block as string
15) @user.save(false) ---> this false bypasses all model validations
16) Conditional validations :- Railscast-41
--------------------------
validates_presence_of :password, :if => :should_validate_password?
validates_presence_of :country
validates_presence_of :state, :if => :in_us?
attr_accessor :updating_password
def in_us?
country == 'US'
end
def should_validate_password?
updating_password || new_record?
end
# in controller
@user.updating_password = true
@user.save
# or...
@user.save(false)
17) with_options :-
---------------
user.validates_presence_of :password, :if => :should_validate_password?
user.validates_confirmation_of :password, :if => :should_validate_password?
user.validates_format_of :password, :with => /^[^\s]+$/, :if => :should_validate_password?
===
with_options :if => :should_validate_password? do |user|
user.validates_presence_of :password
user.validates_confirmation_of :password
user.validates_format_of :password, :with => /^[^\s]+$/
end
def should_validate_password?
updating_password || new_record?
end
18) flash.discard --> discards flash upon redirect
19) map.connect '*path', :controller => 'redirect', :action => 'index' (Should be at the end of routes.rb)
redirect ctrl
def index
render :text => params.inspect
end
http://localhost:3000/scis ---> {"action"=>"index", "controller"=>"redirect", "path"=>["scic"]}
http://localhost:3000/scis/bar ---> {"action"=>"index", "controller"=>"redirect", "path"=>["scic","bar"]}
http://localhost:3000/scis/bar?search=test ---> {"search"=>"test", "action"=>"index", "controller"=>"redirect", "path"=>["scic","bar"]}
render :text => request.request_uri ---> gives the part after http://localhost:3000
20) Naming convention for has_many :through association --> name of the join model
User , Group ---> Membership
Person, Company --> Employement
Category, Product --> Categorization
21) Differentiating between HABTM & has_many :through
i) do I need to store extra information besides ids of both model
ii)do I need to treat join as its own model
If ans of anyone is yes the its has_many :through otherwise HABTM.
22) Check www.coderpath.com
23) sandbox option for rails console rolebacks changes made to the DB on exit.
Ex: rails c --sandbox
rails c production --sandbox
24) Beautifing objects in rails console
>> project = Project.new --> inspects object in a single line
>> y project --> prints the object in yaml format
OR
>> require 'pp' --> Pretty Printing
pp project --> prints object in more readable format
25) Console Tricks -- Railscast 48 (plus some links in show notes section)
26) Alternative ROR API Sites
* railsapi.org
* railsbrain.com
* gotapi.com
* railsmanual.org
* noobkit.com
* ruby.search
* rorapi.com
27) zeus gem (Loads server, console and initializes rails env so that everthing runs under 1 sec)
28) http://reverbhq.com/blog/2012/12/ensuring-data-integrity/
29) Product model :-
belongs_to :category ---> Association of category with product
def create_category_from_name
create_category(:name => new_category_name) unless new_category_name.blank?
end
create_category method is by default provided by rails (create_methodname for any association)
30) Flash notice :-
flash[:notice] can aslo be written as
redirect_to root_url, notice: "Products imported."
31) For generating different color for alternate rows :
<tr class="<%= cycle :odd, :even %>">
cycle is a helper method provided by rails.
32) Coverting block to proc :-
line_items.to_a.sum(&:full_price) === line_items.to_a.sum {|l| l.full_price}
33) <% @cart.line_items.each do |line_item| %>
<%= render :partial => 'line_item' %>
<% end %>
===
<%= render :partial => 'line_item', :collection => @cart.line_items %>
34) logger.debug "Hello world! #{@cart.to_yaml}" (Railscast 56)
# debug, info, warn, error, fatal (Severity from low to high)
35) By default quries are not shown up in production.log so to see it,
In environments/production.rb set:
config.log_level = :debug (default is :info due to which queries are not shown)
36) To display queries in rails console :
create a .irbrc file in root dir
~/.irbrc
--------
if ENV.include?('RAILS_ENV') && !Object.const_defined?('RAILS_DEFAULT_LOGGER')
require 'logger'
RAILS_DEFAULT_LOGGER = Logger.new(STDOUT)
end
37) Overriding of methods can also be done alias_method_chain (Screencast - 62)
Ex: alias_method_chain :valid?(method to over-ride), :without_validation(new method)
38) By overriding the below method in model u can change the id of any object wrt that model. (Screencast - 63) (Check Revised - 63 as well)
def to_param
"#{id}-#{permalink}"
end
Product.find_each :- find_each method fetches the record in batches.
routes.rb
resources :pages, only: [:index, :new, :create] --> will generate the routes for only these pages.
resources :pages, path: "", except: [:index, :new, :create]
By passing path: "" , it will generate the URL's without the word pages in it.
Ex localhost:3000/pages/product-categories will become localhost:3000/product-categories
39) task :greet do
p "Hello World"
end
task :ask do
p "How r u ?"
end
task :abc => :greet do
p 'Task abc called'
end
> rake abc
Calls :greet tak first then calls task :abc
40) task :winner do
user = User.find(:first, :order => 'RAND()')
puts "Winner: #{user.name}"
end
rake winner --> Throws error : uninitialized constant User
task :winner => :environment do
user = User.find(:first, :order => 'RAND()')
puts "Winner: #{user.name}"
end
Loads the rails env first.
41) map.connect 'articles/:year/:month/:day', :controller => 'articles', :month => nil, :day => nil, :requirements => { :year => /\d{4}/ }
If no action mentioned then ----> default is index action
Pass optional parameters as nil.
As the routes are being checked from top to bottom, so to avoid this routes getting executed for some other URL like
localhost:3000/articles/show/6 ---> we hould specify some requirements as matching condition.
42) <%= link_to_destroy "Destroy", project_path(project), :confirm => 'Are u sure?', :method => :delete %>
43) respond_to do |format|
format.pdf do
end
end
---> throws error (Undefined method pdf for ActionController) because pdf is not one of the default formats in Rails. So we have to register it.
In any of the config files :-
Mime::Type.register 'application/pdf', :pdf
44) In ProductsController --> For Basic HTTP Authentication (Railscasts - 82) (Pop up box promting for username/password)
before_filter :authenticate
protected
def authenticate
authenticate_or_request_with_http_basic do |username, password|
username == "foo" && password == "bar"
end
end
45) YAML.load_file("#{RAILS_ROOT}/config/config.yml") ---> returns a hash
46) Customized method to print the values of variable in log
logger.debug_variables(binding)
initializer/logger_addition.rb
logger = ActiveRecord::Base.logger
def logger.debug_variables(bind)
vars = eval('local_variables + instance_variables', bind)
vars.each do |var|
debug "#{var} = #{eval(var, bind).inspect}"
end
end
47) Routes by default also generates formatted rotes means routes for different formats (ex : html, rss etc)
check rake routes
48) To execute any kind of format(extns like pdf, rss, xml etc) for any given action, write the below line in routes.rb
map.connect ':controller/:action.:format'
49) RESTful == Hypermedia APIs
50) Caching is by default off in development environment & ON on production env.
config.action_controller.perform_caching = false ---> devleopment
51) If u add any new folders(for ex: services) in app directory then, u have to mention it in the environment.rb file like this
config/environment.rb (or any initializer file)
config.load_paths << "#{RAILS_ROOT}/app/services"
52) See caching in rails (types of caching in rails). One is page caching
We can also expire cache based on a given condition. (Railscast - 89)(Also has a revised episode)
53) One more type of caching in fragment caching in which we cache only a portion of the page instead of the whole page(Page Caching).
Railscast - 90 (Also has a revised episode)
54) Third type of caching is Action Caching.
Suppose there is a before filter like :
before_filter :authorize #---> Method for checking authorization
then if page caching is enabled and once the page is cached then this before_filter will be bypassed
whereas in case of action caching it will not be bypassed means it will executed for every single action.
54.1) Fragment Caching can improved by using touch (Railscasts : 172)
comment.rb
belongs_to :article, :touch => true
articles/show.html.erb
<% cache @article do %>
...
<% end %>
So, here if we only caching articles and not their comments(using :touch => true through the assciation) then comments will not get reflected and cached page for the article will appear.
So, by passing :touch => true through assciation, whenever a comment object is created or altered it touches the article object thereby changing articles timestamp, so the cache for @article auto-expires
<% cache @article do %> means <% cache @article.cache_key do %>
article = Article.first
article.cache_key ===> articles/1-20090606223425
article.touch # this will change the updated_at column for article with current timestamp.
article.updated_at or article.cache_key ===> articles/1-20090606223450
55) content_for :-
You can use the content_for method in your template to store up the content of the block inside the variable :side, so that it can be used later on in the layout.
<% content_for :side do %>
...
<% end %>
application.html.erb :-
<div id="side">
<%= yield(:side) || render(:partial => '...' %>
</div>
56) Debugging Variables in Views
<%= debug @products %>
<%= debug params %>
<%= debug request.env %>
57) reverse_merge! method is used to not to merge any existing params in the given hash.
58) rake -T time --> list all tasks related to Timezone
rake time:zones:all --> list all time zones which can be set in config/application.rb
rake time:zones:local --> Displays local time zone by checking system time.
rake time:zones:us
In config/environment.rb
config.time_zone = "Pacific Time (US & Canada)" -->(i.e; the output of rake time:zones:local)
Rails saves the time as UTC in DB and while displaying it coverts to mentioned time zone.
In rails console :-
>> Product.first.released_at ---> Displays time by translating UTC into Pacific time zone
>> Product.first.released_at_before_type_cast ---> Displays UTC
Watch Revised Episode 106 for more details
59) Detecting change in attribute :-
--------------------------------
p = Product.first
p.name = 'book'
p.changed? => false
p.name = 'pen'
p.changed? => true
p.name_changed? => true (<attribute-name>_changed? method)
p.name_was => 'book'
p.name_change => ['book', 'pen'] (old_name, new_name)
p.changed => ['name'] (Array of attributes that were changed)
p.changes => {'name' => ['book', 'pen']}
But this change method will only work it the attribute value is being changed with setter method.
so if u do
p.name.upcase! => 'PEN'
p.changed => false
p.save => no update query will be fired
But the above problem can be resolved if u call a method named (<attribute-name>_will_change!)
p.name_will_change! => returns old name
p.name.upcase! => 'PEN'
p.changed => true
and all the other change methods will also function properly.
59) scopes are useful because they can be used for chaining. (means we can chain one scope after the other).
class Product < ActiveRecord::Base
belongs_to :category
scope :cheap, :conditions => { :price => 0..5 }
scope :recent, lambda { |*args| {:conditions => ["released_at > ?", (args.first || 2.weeks.ago)]} }
scope :visible, :include => :category, :conditions => { 'categories.hidden' => false }
end
we can do chaining like
Product.recent.cheap
Also, lambda is useful because it becomes active only when it get called. For ex: say our sever has been started a month back then 2.weeks.ago would become (1 month + 2 weeks) ago if we are not using lambda.
Lambda can be written to accept an argument or without any arguments as well.
scope :recent, lambda { {:conditions => ["released_at > ?", 2.weeks.ago]} }
We can also use these scopes of Product model with their association.
Ex: Category.first.products.cheap.recent
We can also use association with a scope.
For ex:- scope :visible, :include => :category, :conditions => { 'categories.hidden' => false }
Product.visible will only output the products which have categories which are not hidden.
We can also do Product.visible.cheap.recent (scope chaining)
We can also append ActiveRecord queries after the scopes like
Product.recent.cheap.where("name like 'a%'")
Product.recent.cheap.all(:order => 'released_at')
60) check : rake -T gems
rake gems:unpack --> unpacks the gem inside vendor directory
rake gems:build --> generates the code for native gems
61) caching through an instance variable :-
def products
@products ||= Product.find(:all, :conditions => conditions)
end
The above will fire the query only once & return the cached instance variable for every other request.
62) Get browser details of a user by using the gem : browser_details
https://github.com/gshutler/browser_details
63) Anonymous scope :-
------------------
def find_products
scope = Product.scoped({})
scope = scope.scoped(:conditions => ["products.name LIKE ?", "%#{keywords}%"]) unless keywords.blank?
scope = scope.scoped(:conditions => ["products.price >= ?", minimum_price]) unless minimum_price.blank?
scope
end
64) Rails.cache ---> added in Rails 2.1 which is a much lower level cache and can be used to cache anything not only view layers.
(Railscast - 115)
Rails.cache.write('date', Date.today) --> Writes data onto the cache
Rails.cache.read('date') --> Reads data from the cache
Rails.cache.fetch('time') { Time.now } --> Writes for the first time then reads on subsequent request
Ex :- To cache all the categories
def self.all_cached
Rails.cache.fetch('Category.all') { all }
end
Can also fetch newly created categories, by destroying the cache on callback & creating again.
Rails.cache.read('date') --> Destroys data from the cache
65) Rails.cache is a normal hash
But for 3 differnt servers it will create a problem(cache gets created on only 1 server)
So, a better way to store is to set up mem cache server(mem_cache_store) , point the app to that server to get cache
cache = ActiveSupport::Cache.lookup_store(:mem_cache_store)
cache.fetch('time') { Time.now }
We can also set expiry time on the cache if we are using mem_cache ,so that it destroyed in 5 secs & gets newly created since we are using fetch method.
cache.fetch('time', :expires_in => 5) { Time.now }
66) simple_format is a helper method that recognizes line breaks within the text. (Railscast - 117)
<%= simple_format(h(@page.content))%>
Similar to simple_format there is one more helper method : textilize (Ex : <%= textilize @page.content %>)
There is another gem RedCloth(Version 3.3) which can be used for test styling instead of the helper method : simple_format
67) Raising an error explicitly.
def show
if params[:permalink]
@page = Page.find_by_permalink(params[:permalink])
raise ActiveRecord::RecordNotFound, "Page not found" if @page.nil? #----> Throwing an exception explicitly
else
@page = Page.find(params[:id])
end
end
routes.rb
map.static ':permalink', :controller => 'pages', :action => 'show'
---> matches http://localhost:3000/about
68) Liquid is a templating languague which is used to bind dynamic content inside static pages. (Railscast - 118)
69) We can access RDoc in our local system by using command
> gem server
Then RDoc gets rendered in port 8808 and can accessed using the link :- http://localhost:8808
70) populator gem is used to populate the database with large number of records with random data.
This gem cannot be used to generate email_ids or phone nos or postal code etc, so there is another gem for that known as faker.
71) <%= request.subdomains.inspect %>
Gives an array of subdomains from the request object.
Check the subdomain-fu gem for using subdomain in ur rails website.
72) Creating association for same model but with a different name to tell different relationship
invitation.rb model :-
belongs_to :sender, :class_name => 'User'
has_one :recipient, :class_name => 'User'
73) Seeting layout inside a method :
self.class.layout(@current_blog.layout_name || 'application') --> For Blog object having layout_name as a column in blogs table
74) To find Rails environment for inside of a Rails app
env = Rails.env
75) system method is used to execute system commands for inside of a Rails app
system "/usr/bin/rake #{task} #{args.join(' ')} --trace >> #{Rails.root}/log/rake.log &"
& at the end is used to run the rake task in background
>> is used to put the log in a seperate log file.
76) MemCache class can be used for client server communication. (Railscast - 128)
77) You can also go back from a action by using :- redirect_to :back
Ex:
def create
current_cart.cart_items.create!(params[:cart_item])
flash[:notice] = "Product added to cart"
redirect_to :back
end
the value stored in :back is actually request.env['HTTP_REFERER'] which is sent by the browser.
Ex : Good Example of Shopping Cart (Railscast - 131)
cart_items_controller.rb
def create
current_cart.cart_items.create!(params[:cart_item])
flash[:notice] = "Product added to cart"
session[:last_product_page] = request.env['HTTP_REFERER'] || products_url
redirect_to current_cart_url
end
carts/show.html.erb
<% if session[:last_product_page] %>
<%= link_to "Continue Shopping", session[:last_product_page] %> |
<% end %>
78) To load all the rake file in one line :
Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
79) To vendorize a gem u need to use the below command from vendor/gems dir
app/vendor/gems> gem unpack gem_name_version
80) flash.delete(:notice) means flash the notice then delete the flash message, so that it doesnot get carried over to the next request.
81) respond_to do |format|
format.html { redirect_to @review.product } ---> renders show.html.erb
format.js ---> show.js.erb
format.pdf ---> show.pdf.erb
..etc
end
82) To create a function for a jQuery element use jQuery.fn.<function_name>
jQuery.fn.submitWithAjax = function() {
this.submit(function() {
$.post(this.action, $(this).serialize(), null, "script");
return false;
})
return this;
};
$(document).ready(function() {
$("#new_review").submitWithAjax();
})
83) To reset a form in jQuey, u can reset method.
$("#new_review")[0].reset(); --> [0] since $("#new_review") returns an array of jQuery Element.
84) Memoization :- (Railscast - 137, Revised episode available)
--------------
Its an alternative to caching instance varible.
old :- @file_size ||= calculate_filesize
new :-
class Product < ActiveRecord::Base
extend ActiveSupport::Memoizable
belongs_to :category
def filesize(num = 1)
# some expensive operation
sleep 2
12345789 * num
end
memoize :filesize
end
Memoization is deprecated from Rails 3.2.8 so u can use memoist gem for this as an alternative
OR
class Product < ActiveRecord::Base
def filesize(*args)
@filesize ||= {}
@filesize[args] ||= calculate_filesize(*args)
end
private
def calculate_filesize(num = 1)
sleep 0.5
4815162342 * num
end
end
85) t method means translate method of I18n is available only on controllers & views , to access the same at other places use
I18n.translate --> Railscast - 138
86) There are few ways to create nested routes :- (Article --> has_many Comments)
1) map.resources :articles do |article|
article.resources :comments
end
2) map.resources :articles, :has_many => :comments (Make sure use correct routing paths in views) --> Railscast 139
3) map.resources :articles, :has_many => :comments, :shallow => true
87) application_helper.rb
def admin_area(&block)
if admin?
concat content_tag(:div, capture(&block), :class => 'admin')
end
end
rhtml
<% admin_area do %>
<%= link_to "Edit", edit_product_path(@product) %> |
<%= link_to "Destroy", @product, :confirm => 'Are you sure?', :method => :delete %>
<% end %>
88) Product.find_by_price(3) # => nil
Product.find_by_price!(3) # => Raises RecordNotFound Exception
Product.find_last_by_price(4.99) => Finds last record directly (instead of fetching all records and then displaying the last one)
Product.all(:joins => :category, :conditions => { :categories => { :name => 'Clothing' } }) => We can give the join condition in terms of Hash as well.
89) PayPal for Developers for Testing purpose :- http://developer.paypal.com
90) To render nothing write :
render :nothing => true
91) serialize :params
This will convert the params hash into YAML format and saves it to DB & while retrieving it converts back to hash(means original format), means o/p will always be in the form of i/p.
92) Payment Gateway sites :-
Paypal
authorize.net
93) after_initialize method is used in config files to run something after initialization.
Ex : Initializing payment gateway using active merchant
config.after_initialize do
ActiveMerchant::Billing::Base.mode = :test
::GATEWAY = ActiveMerchant::Billing::PaypalGateway.new(
:login => "seller_1229899173_biz_api1.railscasts.com",
:password => "FXWU58S7KXFC6HBE",
:signature => "AGjv6SW.mTiKxtkm6L9DcSUCUgePAUDQ3L-kTdszkPG8mRfjaRZDYtSu"
)
end
94) ::GATEWAY --> :: is used to prepend before a constant so that it can be accessed from applications root, otherwise it will be accessible from from the scope of current class.
95) gem install ---
Install the gem on your system(can also run some malacious code on ur system or servers)
so to cross check do
gem fetch <gem_name> then
gem unpack <gem_name>
96) rails store -m <template_name> (Railscast 148) See the links in show notes section (Refer : http://m.onkey.org/rails-templates)
rails store -m base_template.rb :- This base_template will contain the commands that we want to run after the new rails project store is created.
base_template.rb :-
run "echo TODO > README"
gem 'RedCloth', :lib => 'redcloth'
gem 'mislav-will_paginate', :lib => 'will_paginate', :source => 'http://gems.github.com'
rake "gems:install"
if yes?("Do you want to use RSpec?")
plugin "rspec", :git => "git://github.com/dchelimsky/rspec.git"
plugin "rspec-rails", :git => "git://github.com/dchelimsky/rspec-rails.git"
generate :rspec
end
git :init
file ".gitignore", <<-END
.DS_Store
log/*.log
tmp/**/*
config/database.yml
db/*.sqlite3
END
run "touch tmp/.gitignore log/.gitignore vendor/.gitignore"
run "cp config/database.yml config/example_database.yml"
git :add => ".", :commit => "-m 'initial commit'"
100)ab command (Appache Benchmark) is used for benchmarking (comparing). Server should be run in production mode while benchmarking.
> script/server -e production -d (-d option is used to detach this process)
> ab -n 100 http://127.0.0.1:3000/processes/list
> ab -n 100 http://127.0.0.1:3000/processes_list
101) Rails 2.3 extras :-
# find in batches
Product.count
Product.find_in_batches(:batch_size => 10) do |batch| ---> batch => array of 100 objects
puts "Products in batch: #{batch.size}"
end
Product.each(:batch_size => 10) do |product| ---> passing single product at a time while loading 10 products at 1 go
puts product.name
end
# scoped_by (Dynamic scopes --> scoped_by_<attr-name>)
Product.scoped_by_price(4.99).size --> Till Product.scoped_by_price(4.99) query is not fired, its fired on .size or .first etc
Product.scoped_by_price(4.99).first
Product.scoped_by_price(4.99).scoped_by_category_id(3).first --> chaining of these dynamic scopes can also be done
# try method (Returns product's name if there's product with price 4.99 otherwise nil instead of NoMethodError)
Product.find_by_price(4.99).try(:name)
product.rb --> Default scope gets applied on every query
default_scope :order => "name"
categories_controller.rb
render 'new' --> action_name
render 'products/edit' --> controller/action_name
products/index.html.erb
<%= render @products %> (Render partial products with collection of products)
products/show.html.erb
<%= render @product %> (Render partial product for a single products)
Checkout release notes for more : http://guides.rubyonrails.org/2_3_release_notes.html
102) If u r writing (redirect_to :id => nil) on a create action like
def create
@commentable = find_commentable
@comment = @commentable.comments.build(params[:comment])
if @comment.save
flash[:notice] = "Successfully created comment."
redirect_to :id => nil ---> will redirect you to the index action of the respective commentable type (Article or photo or event)
else
render :action => 'new'
end
end
103) To get class methods get included when we include a module, add a module named ClassMethods inside that module and place all the methods inside ClassMethods module and add a small hook to get it included means include the methods inside ClassMethods when ever the parent module gets included.
module ControllerMacros
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def it_should_require_admin_for_actions(*actions)
actions.each do |action|
it "#{action} action should require admin" do
get action, :id => 1
response.should redirect_to(login_url)
flash[:error].should == "Unauthorized Access"
end
end
end
end
end
104) Grouping gems for two environments
gem 'debugger', group: [:development, :test]
105) logger.debug { "Article Count: #{Article.count}" }
Putting {} braces besides logger.debug will only excute the code inside {} when the logger is in debug mode.
config/environments/development.rb (log_tags appends the mentioned stuffs into the beginning of the log message)
config.log_tags = [:uuid, :remote_ip, lambda { |req| Time.now }] --> (unique user id, User IP Addr, Time)
config/initializers/log_formatter.rb (Over-riding the below Logger class will allow you to modify the log messages)
class Logger::SimpleFormatter
def call(severity, time, progname, msg)
"[#{severity}] #{msg}\n"
end
end
106) date.to_time -------> 2012-04-08 00:00:00 +0530
But while making queries rails will convert time it to UTC time --> 2012-04-08 05:30:00
date.to_time_in_current_zone ---->Prints the Time in UTC -> Sun, 08 Apr 2012 00:00:00 UTC +00:
So, always check the time that's in the query.
107) Always set whitlisting to true
config/application.rb
config.active_record.whitelist_attributes = true
so that nobody is able to access any protected attributes like is_admin through mass assignment.
Use attr_accessible in all the models for the attributes that a user can modify. (attr_protected --> attributes that a user cannnot access.)
108) To access routes in rails console use
> app.products_path --> "/products"
> app.get _ or app.get "/products" --> select * from products --> 200 (Success Code)
> app.class --> ActionDispatch::Integration::Session
> app.cookies --> gives u what cookies were set
> app.response.headers --> Gives response header
> app.response.body --> Response body
> app.assigns(:products).size --> Gives u the instance variable which was set on the last request
109) By default the rails console prints the sql query which is being fired in the console like
Product.count ---> Select count(*) from products
To off it just set ActiveRecord::Base.logger.level to anything greater than 0.
Ex : ActiveRecord::Base.logger.level = 1
110) To set the default behaviour of rails console create a file at ~ named .irbrc, this file will be loaded whenver a rails console is loaded
This is for apps having rails < Rails 3.2
> touch ~/.irbrc
#!/usr/bin/env ruby
require 'irb/completion' # tab completion in irb
require 'irb/ext/save-history' # To enable saving history of previous commands
IRB.conf[:PROMPT_MODE] = :SIMPLE
IRB.conf[:SAVE_HISTORY] = 1000 # 1000 previous commands
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb_history"
# ActiveRecord::Base.logger.level = 1 if defined? ActiveRecord::Base # To restrict sql query logging
# Prints the object in yaml format
def y(obj)
puts obj.to_yaml
end
# open the called in textmate
class Object
def mate(method_name)
file, line = method(method_name).source_location
`mate '#{file}' -l #{line}`
end
end
Install the hirb gem to see the output of queries in nice table format
gem install hirb
Add the below code in .irbrc file to make use it in every project's rails console (Otherwise can also add this gem to ur gemfile to access this gem in every environment)
# Break out of the Bundler jail
# from https://github.com/ConradIrwin/pry-debundle/blob/master/lib/pry-debundle.rb
if defined? Bundler
Gem.post_reset_hooks.reject! { |hook| hook.source_location.first =~ %r{/bundler/} }
Gem::Specification.reset
load 'rubygems/custom_require.rb'
end
if defined? Rails
begin
require 'hirb'
Hirb.enable
rescue LoadError
end
end
Ex :-
require 'hirb'
Hirb.enable
Product.limit(5)
Rails 3.2 onwards :- (Revised :- 148)
--------------------
In Rails 3.2 create a .railsrc file in ~ and place all the options which u want to apply every time u create a new rails app.
> echo -d mysql --skip-test-unit --skip-sprockets > ~/.railsrc
To see all the available options
> rails new --help
We can also tell what app template to refer after creating a rails project means whats commands to be fired every time a new rails app
is created using -m option
> rails new abc -m app_template.rb
app_template.rb (This is based on Thor gem and its documentation is at : http://guides.rubyonrails.org/generators.html#generator-methods)
----------------
remove_file "README.rdoc"
create_file "README.md", "TODO"
gem "rspec-rails", group: [:test, :development]
run "bundle install"
generate "rspec:install"
if yes? "Do you want to generate a root controller?"
name = ask("What should it be called?").underscore
generate :controller, "#{name} index"
route "root to: '#{name}\#index'"
remove_file "public/index.html"
end
git :init
append_file ".gitignore", "config/database.yml"
run "cp config/database.yml config/example_database.yml"
git add: ".", commit: "-m 'initial commit'"
---------------------------------------------------------------------------------------------------------------------------------------
We can also use app builders using -b option to generate app builders which can override default methods of rails app creation
> rails new abc -b app_builder.rb
app_builder.rb
--------------
class AppBuilder < Rails::AppBuilder
def readme # Overridden method readme
create_file "README.md", "TODO"
end
def test # Overridden method readme
@generator.gem 'rspec-rails', group: [:test, :development]
run 'bundle install'
generate 'rspec:install'
end
def leftovers
if yes? "Do you want to generate a root controller?"
name = ask("What should it be called?").underscore
generate :controller, "#{name} index"
route "root to: '#{name}\#index'"
remove_file "public/index.html"
end
git :init
append_file ".gitignore", "config/database.yml"
run "cp config/database.yml config/example_database.yml"
git add: ".", commit: "-m 'initial commit'"
end
end
To check the list of methods that we can override , check the file :
https://github.com/rails/rails/blob/master/railties/lib/rails/generators/rails/app/app_generator.rb