├── README.md ├── rails_programming ├── advanced_forms_and_activerecord │ ├── active_record_associations.md │ ├── active_record_callbacks.md │ ├── active_record_queries.md │ ├── forms_advanced.md │ ├── project_associations.md │ ├── project_associations_2.md │ └── project_forms_advanced.md ├── apis_mailers_advanced_topics │ ├── advanced_topics.md │ ├── api_basics.md │ ├── api_interfacing.md │ ├── conclusion.md │ ├── mailers.md │ ├── project_apis.md │ ├── project_final.md │ └── project_mailers.md ├── databases_and_activerecord │ ├── active_record_basics.md │ └── project_ar_basics.md ├── forms_and_authentication │ ├── form_basics.md │ ├── project_auth.md │ ├── project_forms.md │ └── sessions_cookies_authentication.md ├── introduction.md ├── introduction_to_rails │ ├── deployment.md │ ├── project_feet_wet.md │ ├── project_lets_build.md │ └── web_refresher.md ├── routes_views_controllers_assets │ ├── asset_pipeline.md │ ├── controller_basics.md │ ├── project_basic_rvc.md │ ├── routing.md │ └── views.md └── sinatra │ ├── project_sinatra.md │ └── sinatra.md └── web_development_101 └── web_development_frameworks ├── introduction_to_frameworks.md ├── project_rails.md └── rails_basics.md /README.md: -------------------------------------------------------------------------------- 1 | # THIS REPO IS ARCHIVED 2 | 3 | Please submit your solutions to the TheOdinProject/curriculum/rails-programming repository 4 | 5 | # Welcome to The Odin Project's Ruby on Rails Course 6 | This repository contains the ruby course for [The Odin Project](https://www.theodinproject.com). 7 | 8 | The Odin Project (also known as TOP), is an open-source community for learning full-stack web development. Our mission is to provide a comprehensive curriculum to learn web development for free. We help our students to learn the skills and build the impressive portfolio of projects they need to get hired as a web developer. 9 | 10 | ## Contributing 11 | We are currently redeveloping this course and would love to have your help. 12 | 13 | To find out more about how you can contribute please read our [contributing guide](https://github.com/TheOdinProject/rails_course/wiki/Contributing-Guide). 14 | 15 | 16 | # Maintainers for this Course 17 | * [Austin Mason](https://github.com/CouchofTomato) 18 | * [Kevin Mulhern](https://github.com/KevinMulhern) 19 | * [Jonathan Yiv](https://github.com/JonathanYiv) 20 | -------------------------------------------------------------------------------- /rails_programming/advanced_forms_and_activerecord/active_record_callbacks.md: -------------------------------------------------------------------------------- 1 | ### Introduction 2 | 3 | Callbacks are a common way for you to execute code at specific times in the life cycle of an Active Record object, for instance just before it is created, after it is saved, or after it is destroyed. These can be very useful if you've got something to execute whenever an object hits one of those lifecycle points, like modifying the user's email to be lowercase when creating her account. Callbacks are a way of saying something like "Hey Active Record, when you've finished creating a new User object, give me a call so I can run this method before anything else happens." 4 | 5 | This is a brief section on a useful topic. The Rails Guide reading provides good coverage of it, so my summary will be necessarily brief. 6 | 7 | ### Learning Outcomes 8 | Look through these now and then use them to test yourself after doing the assignment: 9 | 10 | * What is a callback used for? 11 | * What are the major lifecycle stages of an Active Record object? 12 | * How do you build an "around" callback? 13 | * How do you specify a particular action to run a callback for? 14 | 15 | ### The Life Cycle of an Active Record Object 16 | 17 | Callbacks provide hooks into specific points (either before, after, or sometimes "around") in the life cycle of an object. Those life cycle moments are: 18 | 19 | * **Initialization** -- When the object is first built OR whenever it is reloaded from the database and into memory (so any time you find it in a query). 20 | * **Validation** -- whenever Rails checks if the object is valid. That could be when you're trying to save it or if you've manually run the `#valid?` method. 21 | * **Saving** -- The actual act of saving an already-built object to the database. This is triggered any time the object is saved, not just the first time it is created. 22 | * **Creating** -- The creation and saving of a new object. 23 | * **Updating** -- The updating of an existing object. 24 | * **Finding** -- When you've searched for the object. Often gets triggered by Rails working with objects behind the scenes (e.g. when ) 25 | 26 | You often get three choices for callbacks. Not all object lifecycle steps support all callbacks, but the basic three are (using `create` as an example): 27 | 28 | 1. `before_create` -- Runs the method before the stated action 29 | 2. `after_create ` -- Runs the method after the stated action 30 | 3. `around_create` -- A bit trickier. In this one, you will write a method which actually `yield`'s at some point to the original action. That way you can have code before it and after it and YOU decide at which point the original action gets done. Not entirely common. 31 | 32 | ### Using Callbacks 33 | 34 | To use a callback, you need to "register" it at the top of your Model by using the appropriate method (e.g. `before_create`). You pass that method either a symbol which corresponds to a method name or you could just write the callback as a block then and there. Rails will hang onto that method and call it at the appropriate time. For example: 35 | 36 | ~~~ruby 37 | # app/models/user.rb 38 | class User < ActiveRecord::Base 39 | 40 | before_create do |user| 41 | puts "about to create #{user.name}" 42 | end 43 | 44 | after_create :just_created 45 | 46 | private 47 | 48 | def just_created 49 | puts "just created a user" 50 | end 51 | end 52 | ~~~ 53 | 54 | ### Specifying Callback Characteristics 55 | 56 | Callbacks give you several options for narrowing down or selecting specifically when you want them to run. If you only want to run a callback when a particular controller action calls it, use the `:on` option, which takes either a single symbol or a full array, e.g. `before_create :run_code, :on => [:create, :update]`. 57 | 58 | You can also use conditional logic options `:if` and `:unless` to try a method before running callbacks, for instance: 59 | 60 | ~~~ruby 61 | before_create :run_code, :unless => :method_is_true 62 | 63 | private 64 | 65 | def method_is_true 66 | true 67 | end 68 | ~~~ 69 | 70 | ### Transaction Callbacks 71 | 72 | Sometimes your Rails app will need to interact with an external application (which is inherently imperfect) as a part of the save process. Other times your save will involve juggling several balls at once and, if one fails, they all need to be rolled back. Typically these cases will involve wrapping your database save operation in a "transaction", which means that either all the steps work or they all fail and are rolled back. 73 | 74 | The `commit`ting of a transaction and its potential `rollback` if it fails are both lifecycle events that you can latch onto with callbacks, e.g. `after_commit` and `before_rollback`. This is uncommon, so consider it another one of those "just remember that it's an option" type things. 75 | 76 | ### Assignment 77 | 78 |
79 | 1. Read through the [Rails Guide on Callbacks](http://guides.rubyonrails.org/active_record_callbacks.html) 80 | 2. Read [this post from Samuel Mullen](http://samuelmullen.com/2012/01/guidelines-for-using-activerecord-callbacks/) on guidelines for using callbacks. 81 |
82 | 83 | ### Conclusion 84 | 85 | Callbacks are useful and many, like `:after_create` and `:before_destroy` are pretty common. There's no rocket science here, just a helpful concept. 86 | 87 | ### Additional Resources 88 | This section contains helpful links to other content. It isn't required, so consider it supplemental for if you need to dive deeper into something 89 | 90 | * [WikiBooks Reference on Callbacks](http://en.wikibooks.org/wiki/Ruby_on_Rails/ActiveRecord/Callbacks) 91 | -------------------------------------------------------------------------------- /rails_programming/advanced_forms_and_activerecord/forms_advanced.md: -------------------------------------------------------------------------------- 1 | ### Introduction 2 | 3 | You learned about the basics of building forms in HTML and Rails in previous lessons and you can do a whole lot with that knowledge. But there are also cases when crafting a good user experience demands building a form that handles multiple things (e.g. model objects) at once. Users only like clicking the submission button once so you'd better be able to give them the simple experience they demand. 4 | 5 | In this section, we'll take a look at some of the options you have to make a form handle multiple model objects at once. You'll also learn how to prepopulate a dropdown menu with objects. 6 | 7 | ### Learning Outcomes 8 | Look through these now and then use them to test yourself after doing the assignment: 9 | 10 | * How do you prepopulate a dropdown menu with data? 11 | * What is the difference between the `#select_tag` helper and the `#select` helper? 12 | * What format does the array you input to `#options_for_select` need to be in? 13 | * Why would you need to use a nested form? 14 | * What do you need to change in the model to allow nested forms to create new objects properly? 15 | * How do you whitelist the nested parameters properly in your controller? 16 | * Why can't you just delete something by leaving a form field (e.g. a checkbox) blank (unchecked)? 17 | 18 | ### Prepopulating `select` Tags with Collections 19 | 20 | Rails provides you with a few handy ways of making dropdown menus which already contain data when the form is loaded (otherwise they're not that useful). 21 | 22 | Let's say you want to build a New Post form for your blog but you want to be able to select who the author is from among your list of users. You will need to make a dropdown which submits the user's ID as a part of your `params` hash. So you might populate `@users` in your posts controller: 23 | 24 | ~~~ruby 25 | # app/controllers/posts_controller.rb 26 | ... 27 | def new 28 | @users = User.all 29 | @post = Post.new 30 | end 31 | ... 32 | ~~~ 33 | 34 | The bare HTML way is to build a bunch of ` 42 | <% end %> 43 | 44 | ... 45 | ~~~ 46 | 47 | This creates a dropdown list with each user's name as an option. Your `#create` action will receive an attribute called `user_id` and you can use it to match an author to that post. 48 | 49 | But Rails provides some less verbose ways of doing the same thing, namely using the `#select_tag` helper in conjunction with the `#options_for_select` helper. The `#select_tag` will create the surrounding tag while the `#options_for_select` gives `#select_tag` the array of options it needs. 50 | 51 | `#options_for_select` expects a very specific input -- an array of arrays which provide the text for the dropdown option and the value it represents. So `options_for_select([["choice1",1],["choice2",2]])` creates a couple of option tags, one for each choice. This is great, because that's exactly what `#select_tag` expects for its second argument. The only wrinkle here is that you need to convert your `@users` collection, which has full User objects, into a simple array with just `name` and `value`. That's easy using `#map`: 52 | 53 | ~~~ruby 54 | # app/controllers/posts_controller.rb 55 | ... 56 | def new 57 | @user_options = User.all.map{ |u| [ u.name, u.id ] } 58 | @post = Post.new 59 | end 60 | ... 61 | 62 | # app/views/posts/new.html.erb 63 | ... 64 | <%= select_tag(:author_id, options_for_select(@user_options)) %> 65 | ... 66 | ~~~ 67 | 68 | So just pass `#select_tag` the name it should use for your chosen value and the collection and it will output the exact same thing! 69 | 70 | If you want to avoid the whole `options_for_select` thing altogether and your form is designed to build a model instance (e.g. a Post object), just use the more generic `#select` helper in your view: 71 | 72 | ~~~ruby 73 | # app/views/posts/new.html.erb 74 | ... 75 | <%= select(:post, :author_id, @user_options) %> 76 | ... 77 | ~~~ 78 | 79 | You still need to pass it the `:post` parameter (which indicates that your form is building a Post object) so the `select` tag can get the `name` right... in this case, it will name the tag `