methods. Both Ruby and the Ruby on Rails framework use these object-oriented program- .. Exporting the PDF version of an order is now just a matter of call-. interpreted object oriented. Ruby has borrowed a lot from other programming languages, such as: Smalltalk, Perl, Python, C, C++, PHP, Phyton. “Meticulously pragmatic and exquisitely articulate, Practical Object Oriented Design in Ruby —Avdi Grimm, Author of Exceptional Ruby and Objects on Rails.
|Language:||English, Spanish, Arabic|
|ePub File Size:||30.53 MB|
|PDF File Size:||17.10 MB|
|Distribution:||Free* [*Regsitration Required]|
jinzihao.info - Ebook download as PDF File .pdf), Text File .txt) or read book online. In addition, the book is available for download in DRM-free PDF, Epub, Objects on Rails is a sort of “developer notebook” of some ideas and. Working with Unsaved Objects and Associations (For example, to render a PDF report in a background job). Templates are.
We could inject a fake entries collection into the object and con- tinue to test it as we did before. At that point our specs would break. But do we trust ourselves to call ActiveRecord correctly? This suite will hit the actual database. Separating out an integration test for the Blog You may have noticed some new methods being called in the before and after blocks. Here are the definitions: Keeping as many of our tests as possible in super-fast isolation means we can complete the red-green-refactor cycle in seconds rather than minutes.
Separating unit tests from integration tests puts a clear divider between the tests that verify that our database interactions are doing what we think they are doing. These ensure that the database contents is blown away before and after test runs. It also makes it very easy to run only the fast. Separating out integration tests This is a technique I often use in the apps I work on. DB-bound tests.. How can we continue to test it in isolation? We want to treat Ac- tiveRecord as just another collaborator.
Now we put those words into action. An alias for mocking ActiveRecord In this setup block..
Base derivative. Throwing away tests. Using the ActiveRecord alias We want to simulate the case where the object is invalid.
Then we attempt to publish the post Since validity checking is provided by ActiveRecord. NullDB helpers Rake tasks for testing Now that we have both isolated unit tests and integration tests.. We want shortcuts for running just the unit tests. Then we define a subset which expands to only the integration tests.
Rake tasks for testing We define a FileList. Some Rails practitioners prefer to set up a stricter division between business logic and storage logic. TestTask tasks for each set. Once we have our file lists. Using ActiveRecord objects as data access ob- jects In the code above we constructed a chinese wall between the bits of the model that ActiveRecord provides.
The ActiveRecord object becomes a way to get at the stored data. The business model object delegates its storage to the AR object. But I also think it may be a bit heavyweight for some apps. I think this is a promising technique for separating concerns. A little later on. Piotr Solinicahas a great post about this pattern. The code is fairly short. Takes an optional options hash.: Classes and modules will be queried for their instance methods.
FigLeaf Once the list is compiled. FigLeaf enables us to selectively make public methods inher- FigLeaf continued In a nutshell. The objects can still call these methods internally. Base interface. Those are meth- ods which we exercise in our specs. Using FigLeaf In this code. To get an idea of how it works. Base include FigLeaf hide ActiveRecord:: We also hide a bunch of the more common class-level methods that ActiveRecord adds.
We still have a some test failures as a result of introducing FigLeaf. A named scope for the most recent posts We then change Blog to use this scope when fetching entries. Let me be very clear: Using the Post.
The old code for sorting and limiting entries We remove it. FigLeaf is not intended as a hammer to If you and your app are ready for a bigger step towards true separation of concerns. The Data Mapper pattern completely separates business models from per- sistence concerns.
Given the choice. This separation gives you the ability to make substantial changes to your persistence strategy without affecting your business logic. The Ruby DataMapper project does not yet enable full separation of business objects and mapper objects.
In it business models have no knowledge of how to save themselves. Note that this is not the same as the DataMapper project. To my knowledge. And the future of DataMapper is bright: Exiting Eden The FigLeaf technique demonstrated above is an incremental approach to partitioning business logic from the persistence mechanism. That said. Specifiying default body content To make this pass.. Implementing default content for the post body Now we just need to hook it into the persistence process.
Following a few rules will keep us from inadvertently breaking things in the process: But for simple cases. ActiveRecord hooks are a variation on the Observer pattern. Always call super without parentheses. Leaving out the parentheses tells Ruby to re-use the arguments which were passed into the current method. Always call super. If we need to intercept an ActiveRecord-provided method.
Unless you care about the value of arguments. Not so that the object can stare at itself in the mirror all day. Overriding ActiveRecord save This satisfies our needs just as well.
There are some exceptions. If you need to do some processing after the call to super.. Example JSON representation of a blog post Constructing hyperlinked responses like this one presents us with a prob- lem. But when we render JSON data.
So instead. The LinkExhibit class will take a model object and a template object. But it would be tedious writing exhibits for each kind of model that we come up with.
When we serve a JSON representation of a blog post. Implementing these methods for Post is straightforward: These meth- ods are expected to return the model object with the specified relationship to the receiver.
LinkExhibit applicability For now. By defining explicit finders. Post navigation methods Remember. The context parameter can really be anything which responds to the var- ious helper methods used by exhibits.
In particular. Blog is just an ordinary object. Now we modify PostsController to expose a show method. As such. When we cre- ate a few posts and then point curl at http: Giving Blog an ActiveModel:: Now that Rails officially knows its name. So all we have to do now is define that helper.. Establishing a pattern here! Filtering by tag When a visitor clicks on one of the tags. An Object Model for Tags Looking at the list of use cases.. What sort of functionality does tagging entail?
Tagging a post Before saving a new post. Seeing a list of all tags A visitor to the blog sees a list of all unique tags that have been applied to any post in the blog sidebar. Adding tags OK. When the post is saved.
There are plenty of other ways to use tags. They might separate the keywords with either spaces. The displayed tags are separated by commas. They might acciden- tally enter a tag twice. Specifying tag normalization Specifying TagList behavior with no tags TagList should assist us in converting from the space. Specifying TagList duplicate handling It should normalize the tags to lowercase. YEAST" end it "lowercases the tags" do it. BarlEy" end it "eliminates duplicates ignoring case" do it.
Specifying TagList sorting Spec for combining tag lists That tag overview should probably be in alphabetical order. Implementing these requirements takes considerably less space than we needed to spec them out: TagList TagList. Any class needing access to conversions will then be able to include the Conversion module and have access to all defined converter methods.
A migration to add tags to posts Now we need to tell Post to represent its new tags attribute as a TagList instead of as a raw string. So instead we define a module to act as a namespace for conversion methods.
But adding it to the global namespace would be bad form. Other methods have more tag-specific behavior. Conversions You may have noticed a funny little module named Conversion in the code above. Some of its Array-style methods. We anticipate that we will want access to the TagList converter method from more than one class or module. In order to do that. And if we ever changed the representation of TagList.
When it is read out again. But serializing application objects to YAML can lead to headaches down the road. Recall that in TagList. TagList represents itself internally using an array.
We have to ensure that the TagList code is loaded before access- ing that field. In order to drive out this functionality. When a new Post is created.
ActiveRecord will initialize a TagList object. When it comes time to write the record back to the database. Making Post more tag-aware Now we can attach tags to an individual post.
We could have serialized the TagList object itself to the tags column. In order to safely write an array into a string field and get it out again as an array. An integration test for tags An integration test for tags continued These new specs are satisfied with a trio of new class-level methods on Post: Adding tag query methods to Post That last method is worth a second look.. That comes in handy now. In our master layout. Adding tags to the entry partial Remember that entry.. Adding tags to the new post form We also update the blog entry partial to display any tags that are associated with a blog post.
So this should look fine when rendered We also want to show a top-level list of tags that shows all tags in use on the blog. We add a new section to the sidebar in the main application layout: Enabling the front page to be filtered by tag If a: SimpleDelegator is a generic delegator base class which can work when wrapped around any underlying object. At this point.
The FilteredBlog decorator This class is an implementation detail of Blog. DelegateClass klass. And when we click on one of the tags. We can add tags to a post. Extracting a Taggable role: Wondering about the DelegateClass Blog bit? But there is still a fair amount of tagging-specific code in Since we know that FilteredBlog will always be wrapping a Blog object. Conversions def initialize blog.
There are some other minor differences. This is troubling for two reasons: What if we decide we want to tag entities other than posts? Will we be duplicating this code for every class that can be tagged? A Taggable module But what about when we add other func- tionality. Filtering by tag the Post class. Will every new feature that we add result in adding another dozen lines of code to Post?
What ever happened to the Single Responsibility Principle? For each new feature. But does this really address the root problem? The TaggableRecord module This module will also intercept calls to save. Using a mixin module Instead of using modules included in the class.
When in- jected into an object using Object extend. The only dif- ference is. We define a module for that next: TagList initialization in TaggableRecord This module will be included into objects which already have their own state and methods. So we prefix our private instance variable and method names with an underscore to make naming collisions less likely SimpleDelegator to adorn objects with new functionality. Class-level Taggable methods That takes care of the instance-level functionality..
Relation item. Divesting Post of tagging We are now able to remove a bunch of code from Post: TaggableRelation else item. TaggableRecord end item. For that we define another global conversion method: Taggable end Listing A Taggable conversion method This conversion method lets us apply tagging functionality to record in- stances.
The TaggableRelation module These are pretty much exactly as they were in Post. As we decided earlier. Applying the Taggable role in a template And in the PostsController we apply it to a post which is about to be saved.. Cleaning tag-related code from the Post class In fact. By consistently using the return value of conversion methods throughout our codebase—whether we need to or not—we free ourselves from the men- tal burden of having to remember how a particular conversion works.
We could just as well do this: Why use the return value? We do it for consistency and implementation hiding. To search across or list all tags in the blog. Not only that. We do this even though we know that Taggable extends its argument with a module.. We happen to know because we just wrote it that Taggable actually modifies its argument in place. But in other cases. Migrating tag attributes to a "tags" table Note that we define any ActiveRecord models we need for the data migra- tion within the context of the migration.
This will enable the migration to continue working even if we change or remove those models in future revi- sions. We write a migration that creates the new tables. In order to keep tags nice and generic. We rewrite In order to underscore the fact that these are not full-fledged business models. Now Post contains no tag-related code whatsoever. Constructing a TagStorage repository Currently. We define some bare- bones ActiveRecord models for the new tables.
Before we forget.. Beginning the TagStorage class Loading tags will map across an ItemTag collection to get the names of all the tags applied to the item. From our definition in TaggableRecord. Defining it is our next job. Storing tags is a little more involved.. We include the tags table in the query. Then it must create and delete ItemTag and Tag records accord- ingly. We create a scope which encompasses all ItemTag records which have a type and ID corresponding to the item being tagged.
Our store method must find the difference between the tags currently stored for the item. Taggable case item when:: TaggableRecord item. Taggable item.. But now we have a way to store tags in the database for arbitrary objects: That was a fair amount of code. How does that change now that we are storing tags in the database? Implementing TaggableRelation new to handle "tags" attribute The last TaggableRelation method we need to update is the one that en- ables us to get a list of all items tagged with a particular keyword.
Updating TaggableRelation tagged I will concede that this is a bit nuts. This method turns out to be a bit of a doozy. Otherwise if we tried to create e. Our tagging implementation can change independently of other concerns. Reconsidering Taggable Implementing the Taggable role has been an instructive exercise.
And for an aspect like taggability. We removed one line from Post. Is it worth it? If tomorrow we decided to change to using Redis for our tag store.
As an example. When you can extend a system solely by adding new objects with- out modifying any existing objects. I think if I were to write a blog engine right now. I would keep Taggable as an ordinary module and include it into the Post class.
There are more truly orthogonal concerns which I think would lend themselves well to this dynamic role-extension approach. Looking back over the code we wrote for Taggable. While we wrote a fair amount of new code for this.
Since such a role might well want to intercept ActiveRecord methods like save. Whether through decoration. It would be nice if we could write our models without thinking about crosscutting concern of security. The bottom line is this: It is possible to build up your business objects as composites of small. A controller accessor for the Blog instance blog is private here. Many have noted this as a particularly egregious violation of encapsulation..
Until now. In order to maintain this ruse Rails resorts to the kludgy expedient of copying instance variables one by one from the controller to the view template on render.. Rails tries to make view templates look kind of like fancy controller meth- ods.
We make a similar change to PostsController: Exposing the current post as a controller accessor method We continue to set post directly in the controller actions. Easier refactoring to partials. This is the cheapest. A missing or misspelled method. More informative error messages. If you are interested in exploring more advanced OO approaches to rendering views. We gain a couple of pragmatic bene- fits from calling methods instead of accessing instance variables: A missing or misspelled instance variable will default to nil.
Jealously guarding collections The changes we just made enable us to fix another nagging issue. We accessed a Post object directly from the Post model. We now change PostsController show to find the requested post through the blog.. Accessing a post via the Post class Since we added a blog method to ApplicationController.
It sets up structural coupling between PostsController and Blog. Accessing a post via the Blog instance For this to work But there a couple of problems with it.. A lending library has various collections: Now imagine the the library as an object. The opportunity to pre-load child objects with a reference back to their parent. The opportunity to keep a list of child objects in the parent. Imagine a lending library. I suspect the electronic librarians working inside our virtual library would much rather the patrons used an interface like this: The point is.
The library will allow patrons to use and even borrow the items in its collection. The ability to decide the concrete type of child object to return. They must come to the counter and and present their card before taking an item out of the library.
I admit. They must register for a library card before borrowing items. The ability to control access based on authorization information. Remember the advantages we cited earlier of having a parent object mediate access to its children: In short. That may mean. But even that simple act of delega- tion introduces a seam where more involved processing can be introduced later on.
Given our preference. Here is our partial for rendering entries as it stands now: While there is no branch logic in this partial. Exhibiting from inside the controller First of all. No more remembering to put Taggable around the post whenever we want to work with tags.
An ideal entry partial There are a few differences in this version: Speaking of tags. To avoid this. Now that we have a more fleshed-out Post model. It expects to be called once per action in order to determine what top-level rendering action to take. But now that we are using a controller as the context for the exhibited model. ActionController provides a render method too. The specific Exhibit which might be wrapped around a given model object.
The first dispatch. We alter ApplicationController to always decorate the blog before returning it: The template object within which the model may be presented. Quoting Smalltalk Best Practice Patterns: How can you code a computation that has many cases. It gets more complicated when we look at rendering multiple blog posts in the context of the front page.
Exhibiting the blog object It was easy enough to exhibit a single Post object at the controller level. The second dispatch. In our case. In that context. We need a way to recursively exhibit objects. Base include ExhibitsHelper. Exhibiting the Blog instance at the controller level This alone. If there is a filter.. The naive solution is to keep calling exhibit every time we have a new non-exhibited object to deal with: Recall that earlier we made it possible to present only a subset of posts on the blog home page by filtering by tag: The more code we write.
FilteredBlog instance. We then replace our explicit version in BlogExhibit with a call to the new macro: So once we are confident this works. It refers to a method whose purpose is to return an object. Since they are both intended exclusively The Exhibit. BlogExhibit applicability This definition makes use of a new Exhibit.
In order for blog.. Exhibiting the entry list Is this all we need to do? The return value of Blog entries is a collection an ActiveRecord:: Relation instance. An exhibit for collections What we need is a type of Exhibit which will wrap a collection..
We begin to spec out an EnumerableExhibit class We have the first part of the puzzle now. Sample of the EnumerableExhibit spec Enumerable and Array method.. Because they are implemented in terms of each.. For some of the methods.. Making EnumerableExhibit Enumerable We implement each to wrap each element in exhibit before yielding. Sample of the EnumerableExhibit spec continued This is just a small subset of the full spec..
In order to achieve this behavior. At first. The return value is run through the exhibiting process in order to wrap the result set in a new EnumerableExhibit result set. And indeed. Each matching element if any will be wrapped in appropriate exhibits.. This method takes a one-argument block and returns all elements for which the block evaluates to true. In addition. For example. We handle these cases separately: Enumerable partition returns an array of arrays instead of a simple array..
The complete EnumerableExhibit implementation But it behaves sufficiently similarly for our purposes. This template code now works: Each object in the chain will be transparently wrapped in the appropriate Exhibit objects if any. We can safely call post. Telling the post to render itself When we look at the code to render a post body: Given a line of code like the following: Rendering a post body In effect. That method is defined as follows: Making this work will be our next task.
If we can tell an exhibited Post to render its body. We do this because as of Rails 3. It turns out to be fairly straightforward. If a model implements the method. Not quite yet.. It does indeed. Rendering a TagList Back at the beginning of this chapter. Telling a TagList to render itself Implementing EnumerableExhibit render to render each element Instead of rendering a partial..
Once we upgrade to Rails Now we can write this: We use an ActiveSupport:: Remember that inject is implemented in terms of our each method. But for right now this works well enough EnumerableExhibit works well for rendering collections of render-able objects.
TagList is Enumerable. Un- fortunately. Which means we first need to make the tags collection accessible in the first place. But the tags in TagList are just strings. In fact.. Nor are we sure we want one. Which means it will use the default Exhibit render. So long as it comes after EnumerableExhibit in the list of exhibits. Which we then dutifully provide: TagListExhibit Wait a sec. Exposiong tags in PostExhibit Calling tags on an exhibited Post now gets us the exhibited TagList asso- ciated with that post..
The old post template With a little CSS not shown we can make this work anywhere we show a list of tags. No more cluttering up templates with calls to exhibit.
We made TagList exhibit-able. With these changes. We extracted the wrapping of the post object with Taggable into the post exhibit object. Relation exhibit-able. We moved exhibiting of the post and blog object into their respective controllers. By enabling objects in the template to render A little more decoupled and flexible than vanilla Rails style.
We still look for view tem- plates in the conventional places. We still follow the standard Rails workflow of: You are writing view templates Respect controller privacy by accessing instance variables using accessor methods. Scenarios You are beginning a new application Work from the outside in. Define what your screens should look like. A view requires an ActiveRecord-style object in order to function correctly Use ActiveModel to make non-ActiveRecord models compatible with Rails helpers.
Summary Rather than a recap. Organize objects into a roughly tree-like structure with a single root. A set of model methods are only needed in certain con- texts Consider factoring those methods out into a discrete role.
Empower models to mediate access to their children. Listen to the lan- guage of the domain. Leave persistence for later on. Use sensible defaults to keep client code from having to always supply the dependency. Inject only the minimum required interface. Use dependency injection to preserve encapsulation. Validations to add validations to arbitrary models. A model must be displayed using different HTML depend- ing on its state Instead of introducing logic to the view.
You are writing unit tests. You want them to be fast and to enforce good encapsulation Keep your tests isolated from Rails and from classes other than the one un- der test. You need to test that a database query functions correctly Use an integration test separate from your isolated unit tests.
Consider using the Data Mapper pattern. You need to persist a model to the database Treat ActiveRecord as a private model dependency. SUMMARY You are developing a complex view with many models Consider using the Presenter pattern to aggregate the needed models into a single object representing the whole view.
A model needs to hook into various persistence lifecycle events Prefer to override ActiveRecord methods rather than using callbacks. The logic matching Exhibits to models is getting compli- cated Enable Exhibit classes to self-determine what models they are applicable to. You need an object to persist between requests Turn the object into an app-wide Singleton initialized at start-up.
They have served their purpose. Refactor to a separate model and table once performance demands it. You want to display the same view with various different scopes applied to the model Use decorators to layer filters on a model.
You have replaced custom code with framework features. Many of these pain points are really canaries in a coal mine. Some of them are techniques I use daily. My hope is that your imagination has been sparked by one or two of these techniques.
I chose a blog application as the demo because I wanted to go with a problem domain anyone would be familiar with. Is all this extra effort worth it? Conclusion Well. In some ways a blog app was a terrible choice for demonstrating these tech- niques.
Your project is not a Rails project. Thanks for reading. As a project scales. Disciplines like isolated tests. More than showing you a set of patterns and practices. This should not be a cause for consternation and fear. That may mean building new abstractions upon the foundation Rails gives you. And in the pro- cess.
Rails is not the framework. I hope you get some value from it. If you have questions. There is very little new under the sun. Appendix A: Further reading There has been a surge of interest in applying classic Object Oriented prin- ciples to Rails development lately. Here are some starting points for further reading. Cleverly disguised as a book about Smalltalk.
Every web application devel- oper should have a copy of this book within easy reach. Here are some reading suggestions to get you started learning about DCI. The right way to code DCI in Ruby. He also explores what a more deliberately Object-Oriented web frame- work in Ruby might look like. The Exceptional Presenter. A pattern from the. Better Ruby Presenters. An Additional layer example.
Simplifying your Ruby on Rails code: Presenter pattern. A ret- rospective look at the experiences Jay and others had applying Presenters to various projects. Simple Presenters. Among other interesting implications.
Blow Up Your Views. Jeff encoded the concepts intro- duced in this presentation in his Draper gem. For understanding how the Rails puzzle fits together. Appendix B: Acceptance Tests Here is the acceptance test suite for the demo application.
Step implemen- tations and supporting files can all be found in the demo application source code. The acceptance suite I painted the cat! Post many entries When I post the following entries in order: Basic Blog As a drying paint enthusiast I want to publish blog entries So that my friends can enjoy my fascinating hobby Scenario: Post a photo When I post an entry with these values: The acceptance suite continued Having trouble choosing between Decorators and dynamically adding mod- ules to objects?
Composing an adventure Consider an adventure game. Character describe A Character can look. Character class A Character can be described: Dynamic Module Extension This section adapted from a blog post originally published January Appendix C: You can see a lightning bug.
You hear a distant waterfall. You can see a guttering candle.
The character can also consult all of his senses at once: A jaunty bowler cap sits atop your head.. You can see a guttering candle.. A simple example is a hat: BowlerHatDecorator At each turn of the game.
You smell egg salad. Characters can have various effects conferred upon them by items. Your eyes glow dull red. You can see the ravenous bugblatter beast of traal. InfravisionPotionDecorator While the character is experiencing the effects of an infravision potion. It enables your character to see in the dark. But never mind that: The Character observe method calls look—but since the wrapped ob- ject has no knowledge whatsoever of the InfravisionPotionDecorator.
Double yuck! Modules to the rescue In Ruby. Beginners tend to think TDD is scary and complicated. Real TDD means writing tests in Ruby before implementing features, but the principle is the same.
But what if you want to override the default behavior? Here is where it is helpful to have two terminal sessions going in different tabs. There is no need to restart your application server to see the new behavior. If you need to start the server: The code is buried deep in the Rails framework.
However, if you know the convention and the technique for overriding it, you have both convenience and power at your disposal. Web browsers make requests. The beauty and simplicity of the World Wide Web architecture, as conceived by Tim Berners-Lee in , is that the web is nothing more than a request from a web browser and a response from a web server. We can reduce the mystery of how the web works to its simplest components when we investigate the request-response cycle.
Figure The request-response cycle. Inside the Browser We can see the actual request, and the actual response, by using the diagnostic tools built into the web browser. Start the application server if it is not already running: Even if you prefer Mozilla Fire- fox or Apple Safari, try this in Chrome, so you can follow along with the text. Alternatively, you can clear the browser cache. Select the Network tab in the Developer Tools View.
There is only one: The request is composed of: Viewing a request in the Developer Tools View. Now try requesting the home page by entering the URL http: For that, go to the server logs or the console window.
Notice how the diagnostic messages in the console window match the headers in the browser diagnostic view. Notice there are no console log messages for pages delivered from the public folder. Document Object Model What happens after the browser receives a response from the server? It provides a structural representation of the document. Here is a diagram that shows what happens in the server during the request- response cycle.
You learned earlier that, from the perspective of a software architect, Rails is organized to conform to the model—view—controller software design pattern. The MVC design pattern is optimal for web applications and is a central organizing principle for Rails. The MVC design pattern originated in the design of desktop applications.
We can see the reason for the quibble in the next diagram. The diagram shows the MVC architecture as part of the Rails software stack. At the base of the stack is the web browser. Despite the quibble about nomenclature, the architecture is well understood and used by all Rails developers. The controller will obtain any needed data from a model. After obtaining data, the controller will render a response combining data from the model with a view component that provides markup and layout. The model, view, and controller classes you create will inherit behavior from parent classes that are part of the framework, so you will have less code to write yourself.
In most Rails applications, a model obtains data from a database, though some models obtain data from a remote connection to another server. For example, a User model might retrieve a user name and email address from a local database. The controller can obtain data from more than one model if necessary. A controller can have more than one action. For example, a User controller might have actions to display a list of users, or add or delete a user from a list.
We use the terms action and method interchangeably when we talk about a Rails controller; to be precise, controller actions are implemented as methods.
An index view might show a list of users. In many controllers, on com- pletion, the destroy action will redirect to the index view, and create will redirect to either show or new. This conceptual overview will be easier to grasp when you actually see the code for a model, view, and controller.
You can leave it in place. Viewing request headers in the Developer Tools View. Model—View—Controller in Rails. Model—View—Controller stack in Rails.
Our goal is to build a practical web application that you can really use. We can create the routes, model, view, and controller in any order. All must exist before our web application will respond to a request for a home page.
The Name Game Much of the art of programming lies in choosing suitable names for our cre- ations. In Rails, there is often a model with the same name as a controller though a controller can use data from multiple models.
Replace the contents with this: It will be become familiar soon and you can look up the details in the reference documentation, RailsGuides: Routing from the Outside In. Model Most Rails models obtain data from a database. When you use a database, you can use the rails generate model command to create a model that inherits from the ActiveRecord class and knows how to connect to a database.
This simple class provides an easy introduction to Ruby code. Software architects call these abstrac- tions objects. In Ruby, everything we create and manipulate is an object.
Ruby makes it easy for a method to return data when called; the value assigned by the last statement will be delivered when the method is called. The variable is named on the left side of the equals sign; a value is assigned on the right side.
We call the equals sign an assignment operator. Not surpris- ingly, a number also can be assigned to a variable, either a whole number an integer or a decimal fraction a float.
More interestingly, any Ruby object can be assigned to a variable. We can create our own objects, as we have by creating the Owner class.
Or we can use the library of objects that are supplied with Ruby. The Rails API gives us additional classes that are useful for web applications. Learning the syntax of Ruby code gets you started with Ruby programming; knowing the API classes leads to mastery of Ruby. It is described in the Ruby API reference documentation. The Date class has a Date.
You can see this syntax when we assign Date. The Date. Imagine a September birthday. You must use Date. If you enter a date in the format Date. When the Date. The Date class can perform complex calendar arithmetic. The variables birthdate and today are instances of the Date class. The if Then we subtract today from birthday.
This shows you the power of programming in Ruby. Notice that I needed 16 paragraphs and over words to explain 15 short lines of code. But without knowing more than this, we can build a simple web application.
View The Owner model provides the data we want to see on the Home page. In a typical application, one controller can render multiple views, so we make a folder to match each controller. Or use the Unix mkdir command: Some experi- enced developers prefer to add gems that provide the Haml or Slim templating engines. As you might guess, a View that uses the Haml templating syntax would be named new. This markup allows us to insert Ruby code which will be replaced by the result of evaluating the code.
You may have noticed that we refer to the Owner model with the variable owner. It will be clear when we create the Visitors controller why we use this syntax a variable name that begins with the character is called an in- stance variable. The Rails implementation becomes useful if the name is retrieved from a database or created programmatically.
There is no way to display a calculation using only static HTML, so Rails gives us a way to display the birthday countdown calculation.
Controller The Visitors controller is the glue that binds the Owner model with the Visi- torsController new view. In this context, the character is only a documentation con- vention.
The class name is written in camelCase with a hump in the middle, like a camel so we can combine two words without a space. We create an instance variable named owner and assign an instance of the Owner model. Keep in mind the purpose of the controller. Each controller action method responds to a request by obtaining a model if data is needed and rendering a view. The new method is deceptively simple. Hidden behavior inherited from the ApplicationController does all the work of rendering the view.
We can make the hidden code explicit if we wish to. It would look something like this: Rails often offers default behavior that looks like magic because the underlying implementation is hidden in the depths of the Rails code library.
Revealing the hidden code, we see that invoking the new method calls a render method supplied by the ApplicationController parent class. The code underlying the render method is complex. Rails takes care of the rest. As you gain experience, you can dive into the Rails source code to unravel the magic.
Scaffolding This tutorial aims to give you a solid foundation in basic concepts. The model— view—controller pattern is one of the most important. For example, Rails Guides: Students often use scaffolding to create simple Rails applications. Enter the command: Dynamic home page shows days until a birthday.
And the underlying code conforms to the conventions and structure of Rails. Git At this point, you might have the Rails server running in your console window. You might think you have to enter Control-c to shut down the server and get the command prompt. You can open more than one console window. Your terminal application lets you open multiple tabs so you can easily switch between windows without using a lot of screen real estate.
It is convenient to have a console window open for the server and another for various Unix commands. Before we do any more work on our tutorial application, we need to learn about troubleshooting and debugging. Use the git status command to check: Interactive Ruby Shell There will be times when you want to try a snippet of Ruby code just to see if it works. IRB is a Ruby interpreter that runs from the command line.
It executes any Ruby code and provides an immediate response, allowing you to experiment in real-time. If you enter a valid Ruby expres- sion, the interpreter will display the result of evaluating the expression.
Try simple arithmetic: You are using your computer for simple math. Maybe you can delete the calculator app from your phone. IRB will evaluate any Ruby expression and helps you quickly determine if syntax and logic is correct. Actually, IRB can handle multiple lines of code. Try it: Pry is a powerful alternative to the standard IRB shell for Ruby. As you gain experience, you might take a look at Pry to see what the enthusiasm is all about. Your application will be running as if the application was waiting to respond to a web request.
Then you can expose behavior of any pieces of the web application. Loading development environment Rails 4. The prompt shows it is ready to evaluate an expression. Then we can use the Owner. Each instance is a unique object with its own data attributes but the same behavior as other objects in- stantiated from its class. The bits that were organized to create the variable name will evaporate into the ether. Enter Control-d or type exit to quit the Rails console.
The Rails console is a useful utility. It is like a handy calculator for your code. Use it when you need to experiment or try out short code snippets.
Rails Logger As you know, a Rails application sends output to the browser that makes a web request. On every request, it also sends diagnostic output to the server log file. Scrolling the console win- dow is a good way to see diagnostics for every request. You can add your own messages to the log output by using the Rails logger. You could see how the application behaves, step by step. The Rails logger is the best tool for the job. In a controller, you can use the method logger on its own.
In a model, you have to write Rails. You can use any of the methods logger. Log messages written with the logger. If you want your log messages to stand out, you can add formating code for color: Debugging Rails Appli- cations.
Revisiting the Request-Response Cycle Earlier, when we investigated the request-response cycle, we looked in the server log to see the response to the web browser request. We can see evidence of the model-view-controller architecture. Our debug statements show we enter the new method and reveal the value of the Owner name. As we learned, the model-view-controller architecture is an abstract design pat- tern.
Now we can see it as activity in the server log. Error page. In the console log, the stack trace will show everything that happens before Rails encounters the error: There are times when it pays to carefully read through the stack trace line by line, but most often, only the top line of the stack trace is important. The point of this exercise is to encourage you to read the top line of the stack trace and use it to diagnose the problem.
However, there is a better way to force your program to halt, called raising an exception. Rails includes various exception handlers to display errors in production so users will see a helpful web page explaining the error. Check the status to make sure: By all means, if you love the precision and order of programming languages, dive into the study of Ruby from the beginning. Reading Knowledge of Ruby What you need, more than anything, when you start working with Rails, is reading knowledge of Ruby.
It will not be a model, view, controller, or any other standard component of Rails. The jaws that bite, the claws that catch! Beware the Jubjub bird, and shun The frumious Bandersnatch! But it is unclear how the author intends anyone to use the code. In this case, I just want to give you some code that illustrates typical Ruby syntax and structure.
Code is only strings of characters. But some strings have special meaning for everyone and all others are arbitrary words that only have meaning to an individual developer. Some made-up words will be obvious because they are just too idiosyncratic to be part of the Ruby language.
There is only one way to be sure which words are part of the Ruby language: Check the Ruby API. You can use IRB to try out the example code in the console. The ex. Remember you can use Control-d to exit from IRB. Whitespace and Line Endings Whitespace characters such as spaces and tabs are generally ignored in Ruby code, except when they are included in strings.
Some programming languages Java and the C family require a semicolon as a terminator character at the end of statements. Ruby does not require a semicolon to terminate a statement. Comments Ruby ignores everything that is marked as a comment. Use comments for notes to yourself or other programmers. This is a comment. Code must exactly follow the syntax of a lan- guage. Typos, guesses, and code that is almost-but-not-quite right will simply fail, often without any helpful error messages.
Computers seem intelligent because they can execute code conditionally. You can write a program so that given one set of conditions, certain parts of the code will execute, and given different conditions, other parts of the code will execute. Lastly, programs are written to transform abstractions from one form to another.
When we learn simple arith- metic, we learn we can take the symbols for numbers and add them together to make a different number. Computer programs do more than add numbers; a program can transform words and other abstractions. Assignment In Ruby, like many other programming languages, the equals sign indicates we are assigning a value.
The equals sign is the assignment operator. And name is a variable that stores the value so it can be easily reused. Just as we can assign a value to a variable, we can reassign a new value when- ever we want. That is why we call them variables; the value can vary. Foobar Kadigan' Variables can be assigned strings of letters, numbers, or anything else.
Object-Oriented Terminology Software architects use a common vocabulary to talk about programming lan- guages: You can write code and intuitively grasp the meanings. Or you can gain an understanding by applying metaphors. Houses For example, some programming textbooks attempt to explain a class like this: A blueprint for a house design is like a class definition.
All the houses built from that blueprint are objects of a class we could call House. Vehicles Or: Vehicles can have attributes, like color or number of doors.
They have behavior, or methods, like buttons that turn on lights or honk a horn. A class definition is like a cookie cutter. Bits in the computer memory are like cookie dough. The cookie cutter makes as many individual cookies as you want.
Each cookie is an instance of the Cookie class, with the same shape and size as the others. Cookies are objects. You can decorate each cookie with sprinkles, which are attributes that are unique to each instance.
Running a program is like baking. The cookies change state from raw to cooked. Sticking a toothpick in a cookie is like calling a method. The method returns a result that tells you about the state: Is it done? Limitations of Metaphors Metaphors are imperfect. If baking was like running a program, all the cookies would disappear as soon as the oven was turned off.
What values are possible for the attribute Gender? For many years, Facebook offered two choices, male and female. As Sarah Mei discusses in a blog post, Why Gender is a Text Field on Diaspora, your assumptions have conse- quences when you build a model. They typically represent an abstraction, like an Array or a Hash, which inherits char- acteristics from another abstraction, for example, a Collection.
Terminology such as class and instance describe the abstrac- tions and the relationships among them. For the software architect, classes make it possible to create a structure for complex software programs. There is one class at the apex of the Ruby class hierarchy: BasicObject is a very simple class, with almost no methods of its own.
The Object class inherits from BasicObject. Object provides basic methods such as nil? The example just shows it for teaching purposes. Here is the Example class without the explicit subclassing from Object: Methods get the work done. Any class can have methods. Methods are a series of expressions that return a result a value.
We say methods describe the class behavior. Here we will return the string assigned to the variable name. This example shows how you can override any method inherited from a parent class. This tiny punctuation symbol is a powerful operator in Ruby. It allows us to call a method to get a result.
Sometimes we say we send a message to the object when we invoke a method, implying the object will send a result. For example, you can run this in the Rails console: For example: For example, String has methods reverse and upcase among many others. We could write: These characters are simply a naming con- vention for Ruby methods.
The question mark indicates the method will return a boolean value true or false. In Rails an excla- mation point often means the method will throw an exception on failure rather than failing silently. Initialize Method Objects are created from classes before they are used. When we call the new method, we press the cookie cutter into the dough and get a new object. All the cookies will have the same shape but they can be decorated differently, by sprinkling attributes of different values.
The initialize method is one of the ways we sprinkle attributes on our cookie. The new method calls the initialize method automatically.
Method Parameters Methods are useful when they operate on data. Parameters are placeholders for data values. The values that are passed to a method are arguments. Our initialize method takes name and date arguments: We separate our parameters with commas. For readability, we enclose our list of parameters in parentheses. In Ruby, parentheses are always optional but they often improve readability. We can assign any object to a variable. The variable works like an alias. We can use a variable anywhere as if it were the assigned object.
The variable can be assigned a string, a numeric value, or an instance of any class all are objects. You can assign a different kind of object if you want. Symbol Obviously, we see many symbols when we read Ruby code, such as punctua- tion marks and alphanumeric characters. It is like a variable, but it can only be assigned a value once.
After the initial assignment, it is immutable; it cannot be changed. We can use the initialize method to input data to the object. Attributes are a convenient way to push data to an object and pull it out later. In Ruby, attributes are also called properties. For example, we could write: Instance Variable Inside an object, an ordinary variable only can be used within the method in which it appears.
The scope of a variable is limited to the method in which it is used. Often you want a variable to be available throughout an instance, within any method. The instance variable can be used by any method after the class is instantiated. If you create multiple instances of a class, each will have its own values for its instance variables.
Here we create two instances of the Example class. We use an instance variable when we want a model to be available to the view template. Rails beginners learn the simple rule that you have to use the at sign if you want a variable to be available in the view.
That leads to a question: Why is an instance variable available inside a view? There is a good reason. A Rails view is NOT a separate class. It is a tem- plate and, under the hood, it is part of the current controller object. This example shows us that the programmer and the software architect have different perspectives on a Rails application. Understanding Rails requires an integration of multiple points of view.
In this case, we only assign a value to the variable if no value has been previously assigned. Conditional Conditional logic is fundamental to programming.
Our code is always a path with many branches. If the expression is true, the statements following the condition are executed. If the expression is false, any statements are ignored, unless there is an else, in which case an alternative is executed.
Or if can be followed by a variable that has been assigned a boolean value. Or you can call a method that returns a boolean result. If date is already assigned a value, we assign it to the instance variable date.
Ruby developers like to keep their code tight and compact. This compact conditional syntax is named the ternary operator because it has three components. Here is the syntax: For more Ruby code that has been condensed into obscurity, see an article on Ruby Golf. Ruby golf is the sport of writing code that uses as few characters as possible.
We already know that we can assign a string to a variable: Foobar Kadigan" Single quote marks indicate a string. In the example above, we enclose a space character within quote marks so we add a space to our string. You can eliminate the ungainly mix of plus signs, single quote marks, and space characters in the example above.
Use double quote marks and you can perform interpolation, which gives a new job to the hashmark and curly brace characters: Foobar Kadigan" The hashmark indicates any expression within the curly braces is to be evalu- ated and returned as a string. This only works when you surround the expres- sion with double quote marks. Sometimes you want to create a method that only can be used by other methods in the same class. This is common when you need a simple utility method that is used by several other methods.
Any methods that follow the keyword private should only be used by meth- ods in the same class or a subclass. Ruby provides a protected keyword as well, but the difference between protected and private is subtle and protected is seldom seen in Rails applications.
Computers have always been calculation machines; they are just as important in managing collections. One important type of collection is named a Hash. A Hash is a data structure that associates a key to some value. You retrieve the value based upon its key. This construct is called a dictionary, an associative array, or a map in other languages.
Ruby 1. In a Hash, a trailing colon makes a string into a symbol. If you want to transform a string containing spaces into a symbol in a Hash, you can do it, though the syntax is awkward: Arrays can hold objects of any data type. In fact, arrays can contain a mix of different objects. For example, an array can contain a string and another array this is an example of a nested array. An array can be instantiated with square brackets: See the Ruby API for a full list.
Iterator Of all the methods available for a Ruby collection such as Hash or Array, the iterator may be the most useful. Each item in an Ar- ray, or key-value pair in a Hash, is passed to the block of code to be processed. Block You can recognize a block in Ruby when you see a do A block is a common way to process each item when an iterator such as each is applied to a Hash or Array. The block is like an unnamed method. The two variables are available only within the block.
As each key-value pair is presented by the iterator, the vari- ables are assigned, and the statements in the block are executed. Computer scientists consider a block to be a programming language construct called a closure. Ruby has other closures, including the proc short for proce- dure and the lambda. They are more common in the Rails source code where advanced programming techniques are used more frequently. The key point to know about a block or a proc or a lambda is that it works like a method.
The example code only uses keywords from the Ruby API. Rails has its own API, with hundreds of classes and methods. We say Ruby is a general-purpose language because it can be used for any- thing. Ruby is a great language to use for building a DSL, which is why it was used for Rails. Unlike some other programming languages, Ruby eas- ily can be extended or tweaked. Software archi- tects call this metaprogramming which simply means clever programming that twists and reworks the programming language.
Some of the most powerful gems add their own DSLs to your project. For example, the Cucumber gem provides a DSL for turning user stories into automated tests. Adding Rails, additional gems, and DSLs provides powerful functionality at the cost of complexity. But it all conforms to the syntax of the Ruby language. Spend time with a Ruby textbook or interactive course when you work on Rails projects.
No more fooling around. With the next chapter, we start building a real-world Rails website. Chapter 16 Layout and Views In previous chapters we created a dynamic home page and learned techniques for troubleshooting. This chapter covers a lot of ground, so take a break before jumping in, or pace yourself to absorb it all. The Ruby code will be processed by a templating engine built into Rails.
The output will be pure HTML sent to the browser. That is added by Rails to support turbolinks, for faster loading of webpages. For the most part, everything is ordinary HTML. Where did all the extra HTML come from? The default application layout is where you put HTML that you want to include on every page of your website. Remember when we looked at the hidden code in the controller that renders a view?
YIELD Alternatively, you could tell the controller to render the view without any ap- plication layout: The reference RailsGuides: Layouts and Rendering in Rails explains more about using alternative layouts. Notice that the default application layout contains the Ruby keyword yield.
The content from the view is inserted where you place the yield keyword. For example, you could create an application layout that includes a sidebar. The example above will create three list items, like this: Ruby is an ideal choice for a web application development platform such as Rails because it can easily be used to create a domain-specific language or DSL.
We can add new keywords that produce complex behaviour, creating entire new APIs such as Rails. It turns out that almost any website that accepts user input via a form is vulnerable to a security bug an exploit named a cross-site request forgery.
Rails provides a number of similar features that make websites more secure. Strange new keywords may be part of the Rails API.
Think of it this way: But they serve as shortcuts to produce complex snippets of HTML and content. The Rails default starter application, which we get when we run rails new, provides a barebones application layout. Rails provides the rails generate command to run simple scripts that are packaged into gems.
Viewport The viewport metatag improves the presentation of web pages on mobile devices. The tag is required for either Bootstrap or Zurb Foundation front-end frameworks.
The viewport metatag looks like this: That means adding title and description metatags. Google uses contents of the title tag to display titles in search results. And it will sometimes use the content of a description metatag in search results snip- pets. Good titles and descriptions improve clickthrough from Google searches.
Title and description looks like this: It uses the Ruby ternary operator which maximizes compactness at the price of intro- ducing obscurity. The Rails asset pipeline utility is one of the most powerful features of the plat- form. It offers convenience to the developer and helps organize an applica- tion; more importantly, it improves the speed and responsiveness of any com- plex website.
With multiple stylesheets, the HEAD section of your application layout might look like this: Instead, use the asset pipeline and simplify this. Assets With Rails The asset pipeline consists of two folders: Navigation Links Every website needs navigation links. This is advantageous if we make changes to the location of the link destinations. Some webmasters like to use absolute URLs, specifying a host name in the link, for example http: We include the navigation partial in our application layout with the expression: The second parameter is the route.
For now, we have nothing to add. Flash Messages Rails provides a standard convention to display alerts including error mes- sages and other notices including success messages , called a flash message. Ac- tion Controller Overview. Flash message in Rails. When the page is reloaded or another page is visited, the message disappears. Creating Flash Messages Flash messages are created in a controller.
We can assign other messages, such as flash[: In practice, Rails uses only: Use flash. With flash.
If you use flash. If you use the simple flash directive before a render directive, the message will appear on the rendered page and reappear on a subsequent page after the user clicks a link. In our example above, we really need to use the flash. The flash object is a Ruby hash. Hash is a type of collection. Because we have a collection with possibly multi- ple messages, we need to retrieve each message one at a time.
We learned earlier that all collections support an iterator method named each. Iterators return all the elements of a collection, one after the other. The iterator returns each key-value pair, item by item, to a block. You can add any code to a block to process each item from the collection. The output string will appear as HTML like this: The Flash Messages Partial Flash messages are a very useful feature for a dynamic website.
First, the expression if msg. String serves as a test to make sure we only display mes- sages that are strings. These elements are not unique to a Rails application and will be familiar to anyone who has done front-end development. Notice the main tag: It typically contains links to copyright infor- mation, legal disclaimers, or contact information. Application Layout Our application layout is complete.
Finally we have HTML5 structural elements. For more on CSS, there are thousands of tutorials on the web, but I like these: For now, the simple. The web server may already be running.
Front-end development has grown increasingly important as websites have be- come more sophisticated. And front-end technology has grown increasingly complex, to the degree that front-end development has become a job for spe- cialists. Front-end developers are primarily concerned with: Around the time that Rails became popular, front-end developers at large companies began to share best practices and establish open source projects to bring structure and consistency to front-end development, leading to development of CSS frameworks.
These plug-ins are used to add visual effects and interactivity to web pages. Examples are drop-down menus, modal windows, tabbed panels, autocomple- tion search forms, and sliders or carousels for images.
Even without plugins, jQuery is useful as a high-level interface for manipulating the browser DOM document object model , to make it easy to do things like hiding or revealing HTML elements on a page. Any Rails application can use jQuery because it is included by default in any new Rails application.
Libraries such as jQuery add functionality to server-side applications, such as those built with Rails. All use a variant of the model-view-controller MVC software design pattern to implement single-page applications which function more like desktop or mobile applications than websites.
There are many responsive front-end frameworks to choose from, including: Each adds a library of markup, styles, and standard- ized web page features such as modal windows, pagination, breadcrumbs, and navigation.
Bootstrap is the best-known front-end framework. It is the result of an effort to document and share common design patterns and assets across projects at Twitter, released as an open source project in August Zurb Foundation was released as an open source project in October , after more than a year of internal use at Zurb, a Silicon Valley design consultancy. As a result, CSS rules are ver- bose and often repetitive. As a result, your stylesheets can use variables, mixins, and nesting of CSS rules, just like a real programming language.
Mixins are like variables that let you use snippets of reusable CSS. Nesting eliminates repetition by layering CSS selectors. Bootstrap or Zurb Foundation? Which should you use, Bootstrap or Zurb Foundation? Zurb Foundation has a solid following among Rails developers. It gained an initial advantage because Zurb provides a gem that adds Foundation to Rails.
When Zurb releases new versions of Foundation, the company updates the gem immediately. Recently in January , the Bootstrap team started supporting a Ruby gem that provides a drop-in Sass version of Bootstrap for Rails. Now any preference for Foundation over Bootstrap is primarily a matter of personal taste. Bootstrap has a larger developer community and more third-party projects, as evidenced by a Big Badass List of Useful Twitter Bootstrap Resources.
In its sheer magnitude, this list, from Michael Buckbee and Bootstrap Hero, demon- strates the popularity of Bootstrap and the vitality of its open source commu- nity. Graphic Design Options There are three approaches to graphic design for your Rails application.
Consequently, sites that use Bootstrap or Zurb Foundation look very similar. A third option is to purchase a pre-designed theme for your website. You may have visited ThemeForest or other theme galleries that offer pre-built themes for a few dollars each. Take a look at some of the inexpensive themes for Foundation that you can adapt for Rails: The site Themes for Bootstrap aggregates Bootstrap themes, or you can visit sites such as Start Bootstrap, Bootswatch, or the Themestrap gallery.
Zurb Foundation Gem Zurb Foundation provides a standard grid for layout plus dozens of reusable components for common page elements such as navigation, forms, and buttons.
More importantly, it gives CSS the kind of structure and convention that makes Rails popular for back-end development.
Zurb Foundation is packaged as a gem. Our approach is slightly different from the Zurb in- structions but yields the same results. Note the. This will allow you to use the advantages of an improved syntax for your ap- plication stylesheet. You learned earlier that stylesheets can use variables, mixins, and nesting of CSS rules when you use Sass. Sass has two syntaxes. The Sass project also offers a second, older syntax with indented formatting that uses the extension.
The asset pipeline will preprocess any. The application. Your CSS stylesheets get concatenated and compacted for delivery to the browser when you add them to this directory: If you are familiar with CSS syntax, it may seem odd that the relevant lines are commented out using asterisks. Though they are com- mented out, the Rails asset pipeline reads and understands them. However, in practice, you are more likely to modify the style rules provided by Zurb Foundation.
How you organize your CSS is up to you; the asset pipeline lets you organize your CSS so it is easier to develop and maintain. In general, only large and complex sites need this optimization.
Like the application.