Your SlideShare is downloading. ×
Slides from lecture - Ruby on Rails Short Course: Just Enough Ruby
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Slides from lecture - Ruby on Rails Short Course: Just Enough Ruby

968

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
968
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
12
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. UC Berkeley More Rails: Multi-Model, HABTM, Controller & View tricks CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox
  • 2. Outline (and suggested Rails book chapters*) • Review Lab 2 • Review multi-model associations (Ch. 18) – has_and_belongs_to_many – has_many :through • Model validations (19.1) & lifecycle callbacks (19.2) • More controller (Ch. 21) & view (Ch. 22) tricks • Lab 3: add login & administrator actions to Lab 2 • Project pitches *Chapters refer to 2nd ed. of Agile Web Development With Rails
  • 3. Lab 2 • UI question: add student to course, or course to student? • Note, scaffolding won’t automatically work for multi-model associations • http://www.rubyonrails.org/doc is your friend
  • 4. Review: Testing • What is... – a unit test? – a functional test? – an integration test? • How do you “simulate” user’s actions in a controller test?
  • 5. Review: Simple Associations • What will the tables be called? • What additional column(s) will need to be present (besides those for attributes)? • Why do we have to declare the association in both directions? class Professor < ActiveRecord::Base has_many :courses ... class Course < ActiveRecord::Base belongs_to :professor
  • 6. Associations and the magic of “duck typing” • What if there’s more than one professor whose last name is Fox? • What if ror doesn’t validate? – What would be a safe workaround? • What does the delete do? • Will ror be saved? ror = Course.new(:name => "Ruby on Rails", :ccn => 99999) cs61a = Course.find_by_name("Structure and Interp...") p = Professor.find_by_last_name("Fox") p.courses << c p.courses.delete(cs61a) p.save!
  • 7. Caveat! • This won’t work! why not? • General rule: saving the “parent” object saves the child(ren)...but not vice versa • Fix: save the children separately ror = Course.find_by_name("Ruby on Rails") p = Professor.new(:last_name=>"Sobel", :first_name=>"Will") cs61a.professor = p cs61a.save!
  • 8. Has and Belongs to Many • Symmetric relationship between tables – can use the has_many methods “from either end” – why do you need a separate join table for this? • Recall: simple join table – Compared to regular ActiveRecord model table? – How to create in raw SQL DDL vs. with migrations – C/C tells us how to name it. class Student << ActiveRecord::Base has_and_belongs_to_many :courses ... class Course << ActiveRecord::Base has_and_belongs_to_many :students courses_students course_id student_id
  • 9. Adding attributes to a join table • You can add other columns to a table – but beware, it might be better to make it a full model s = Student.find_by_ucb_sid(99999) c = Course.find_by_name("Ruby on Rails") s<<c s.courses.push_with_attributes(:date_added => Date.today) courses_students course_id student_id date_added
  • 10. has_many :through • If a student has_many courses and a course belongs_to professor, you could argue that a student has_many professors class Student << ActiveRecord::Base has_many :professors, :through => :courses ... s = Student.find_by_last_name("Bodik") p = s.professors students id=3 last_name=Bodik courses id=45 student_id=3 professor_id=7 professors id=7 last_name="Fox"
  • 11. Additional find options for multi-model students = Student.find(:all, :conditions=>['graduation_date < ?',Date.parse("6/1/08")], :include => :courses You can also specify limits and offsets, and oh so much more • :include - Prefetches joined tables. Discuss. • Just to make sure you’re on your toes... – why did I use the “array form” of :conditions clause? – does it matter if I say :courses or 'courses' or "courses"? – what kind of a method call is Date.parse ?
  • 12. Model Validations • A validation asserts the conditions under which some attribute of a model has a valid value • Why not do this in (e.g.) controller when new model object is submitted for creation?
  • 13. Keeping validations with models • model lifecycle specifies well-defined callbacks for ActiveRecord manipulation – allows keeping validation semantics with the model – allows keeping validation code separate from mainline • are those macros, language keywords, or what?
  • 14. How would you use these? • Note convention: save! vs. save (also create, update, ...) • Scaffolding provides a default use via a view helper method errors_for
  • 15. Callbacks Allows Pre and Post Operations
  • 16. Another way to do passwords # Encrypts some data with the salt. def self.encrypt(password, salt) Digest::SHA1.hexdigest("--#{salt}--#{password}--") end def before_save return nil if password.blank? self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}-- #{login}--") if new_record? self.crypted_password = encrypt(password) end Encrypt a password before saving the record • Update fails if filter returns nil • Note use of: – instance/class methods: password, encrypt – predicate methods: blank?, new_record?
  • 17. Action View • A template for rendering views of the model that allows some code embedding – commonly RHTML; also RXML, HAML, RJS – note...too much code breaks MVC separation – convention: views for model foo are in app/views/foo/ • “Helper methods” for interacting with models – model values→HTML elements (e.g. menus) – HTML form input→assignment to model objects • DRY (Don’t Repeat Yourself) support – Layouts capture common page content at application level, model level, etc. (app/views/layouts/) – Partials capture reusable/parameterizable view patterns
  • 18. Helper Methods for Input & Output • Here is a simple view ... – Anatomy: <% code %> <%= output %> – Sanity check: why do we use <% and not <%= for tag helpers? • What about ActiveRecord model-specific form tags? • In the RHTML template: <%= text_field 'student', 'last_name' %> • In HTML delivered to browser: <input id="student_last_name" name="student[last_name]" size="30" type="text" value="Fox" /> • In controller method, can then say: stu = Student.new(params[:student]) Why does this work?
  • 19. model-specific form tag helpers • Recall: <input type="text" id="student_last_name" name="student[last_name]"/> • Related form elements for student attributes will be named student[attr ] – marshalled into params as params[:student] [:last_name], params[:student] [:degree_expected], etc. – i.e, params[:student] is a hash :last_name=>string, :degree_expected=>date, etc. – and can be assigned directly to model object instance – helpers for dates and other “complex” types...magic
  • 20. More sophisticated tag helpers: dropdown menus • Here are some examples • Many more helpers, read the documentation!
  • 21. Partials • Reusable chunk of a view – e.g., one line of a Student table – e.g., form to display/capture Student info that can be used as part of Edit, Show, Create,... – file naming convention: the partial foo for model bar is in app/views/bar/_foo.rhtml • default partial form generated by scaffolding – so edit.rhtml (the edit view) is really trivial, and differs minimally from new.rhtml – but both of them set the local variable student – can set additional local variables for partial using :locals => {:var => value, :var => value } – can use the option :object => var to set it from an object other than @student
  • 22. What about a collection? • Common idiom: @students.each do |student| render :partial => 'student' • Captured by: render :partial => :student, :collection => @students – other options allow specifying “divider” template
  • 23. Putting it all together: Validation error reporting in views: CSS+HTML+Rails • form partial sets ID, class of specific elements – text_field helper conditionally wraps HTML element in <div class="fieldWithErrors"> – error_messages_for (in 'form' partial) wraps @student.errors (set by ActiveRecord validation callbacks) with <div id="errorExplanation"> • Default layout for class (app/views/layouts/students.rhtml) – generated by script/generate scaffold student – pulls in stylesheet scaffold.css (generic scaffolding styles) that define visual appearance for element ID errorExplanation and class fieldWithErrors Yow!
  • 24. Controller: rendering • So far you’ve relied mostly on the implicit rendering done after controller method – Convention over configuration: implicit render looks for template matching controller method name and renders with default layouts (model, app) • But we can do other things instead... – exactly one render permitted from controller method – in fact, required; why? (hint: MVC)
  • 25. Controller tricks • redirect_to allows falling through to different action without first rendering – fallthrough action will call render instead – works using HTTP 302 Found mechanism, i.e. separate browser roundtrip • example: create method – success: redirect to list action – fail: render the new action (without redirect)...why?
  • 26. The Session Hash • Problem: HTTP is stateless (every request totally independent). How to synthesize a session (sequence of related actions) by one user? • Rails answer: session[] is a magic persistent hash available to controller Actually, it’s not really a hash, but it quacks like one – Managed at dispatch level using cookies – You can keep full-blown objects there, or just id’s (primary keys) of database records – Deploy-time flag lets sessions be stored in filesystem, DB table, or distributed in-memory hash table
  • 27. The Flash • Problem: I’m about to redirect_to somewhere, but want to display a notice to the user • yet that will be a different controller instance with all new instance variables Rails answer: flash[] – contents are passed to the next action, then cleared – to this action: flash.now[:notice] – visible to views as well as controller • Strictly speaking, could use session & clear it out yourself
  • 28. Controller predicates: verify • A declarative way to assert various preconditions on calling controller methods • You can check selectively (:only, :except) for... – HTTP request type (GET, POST, Ajax XHR) – Presence of a key in the flash or the session – Presence of a key in params[] • And if the check fails, you can... – redirect_to somewhere else – add_to_flash a helpful message • A simple example in our simple controller
  • 29. More General Filters • Code blocks that can go before, after or around controller actions; return Boolean before_filter :filter_method_name before_filter { |controller| ... } before_filter ClassName – options include :only,:except, etc. – multiple filters allowed; calls provided to prepend or append to filter chain – subclasses inherit filters but can use skip_filter methods to selectively disable them • If any before-filter returns false, chain halted & controller action method won’t be invoked – so filter should redirect_to, render, or otherwise deal with the request • Simple example: authentication
  • 30. Lab 3 1. Add logins and passwords to Lab 2 – Use virtual instance methods or model callbacks to implement passwords – Add unit tests to check password functionality – Add functional tests to check login being enforced – Note: for projects, you’ll probably use acts_as_authenticated which we’ll describe later 1. Add an “is administrator” flag to Student model using a migration 2. Restrict certain controller actions (your choice) to admin only • Redirect to login page with a helpful message (hint: use the flash) if violated • Add functional test to check that only admin can do those actions

×