Up and Running
Who Am I?
Prolific Module Author
1 wife, 3 kids, 1 dog
Type 1 Diabetic
- How long have you used CFML?
- How long have you used ColdBox?
- What are you hoping to get out of this workshop?
- Any specific questions you hope will be answered?
Installation and Setup
- Get started "quickly" using the `quick-with-auth` template on ForgeBox.
- Configure our Application.
- Take a tour of what is provided from the template.
- Scaffold a quick-blog-example app from the quick-with-auth template.
- Configure Quick in your .env file and application to work with your database.
- Run your migrations against your database.
- Start Server and ensure that registration and logging in is successful.
The Quick Philosophy
Map to a database table.
Expose columns as properties.
Expresses relationships between entities
Can define custom logic as needed
Let's Tour our App!
- Add a new migration to add firstName and lastName columns to the database.
- Add firstName and lastName attributes to the User entity.
- Add fields to the registration form for the new fields.
- Validate that the new fields are required when submitting the form.
- Save all the registration fields to the database.
- Show the user's full name on the navbar when logged in.
Goal: Capture addition user information in the registration form.
Returns an array of entities
- Create a migration for a posts table.
- Create a Quick entity for a Post.
- Create a posts handler and index action to show all posts.
- Show all posts on the index view.
- Provide an empty state view in posts.index.
- Add a link to create a new post.
- Link to the new posts.index route from the navbar.
Goal: Show all existing Posts
Define how two entities are connected.
Extendible at runtime.
Can be eager or lazy loaded.
- Create a new form for creating a Post. Ensure the user must be logged in to access it.
- Handle validation and saving of a new Post. On success, relocate to the posts.index page with a cbmessagebox message.
- Show the author's name on the Post card.
- Create a second Post from the UI. Notice the Posts are sorting in ascending order by id.
- Order the posts in descending order by createdDate.
Goal: Create a new Post from the UI
Returns a single entity
- Create a new action for show to load the Post with the given id in the url.
- Display the post in a new posts.show view. Include a link back to the posts.index page.
- Link the title of each Post on the posts.index page to the new posts.show route.
- Handle the EntityNotFound exception thrown by Quick to show a 404 page.
Goal: Display a single Post
- Add an edit form. Ensure that only the author of a Post can view this form.
- Handle validation and updating of Posts. Ensure that only the author of a Post can edit the Post. Relocate back to the posts.show route.
- Add a link to delete a Post on the edit page when the logged in User is the author of the Post.
- Handle deleting a Post. Ensure that only the author of a Post can delete the Post. Relocate back to the posts.index route.
Goal: Allow for editing, updating, and deleting of Posts
See You Tomorrow!
- Create a migration to create a comments table.
- Create a Comment entity.
- Add a relationship from Comment to Post and from Comment to User.
- Add the inverse relationship from Post to Comment.
- Show the new comment form on the posts.show view when the user is logged in.
- Validate and create a Comment associated with a Post. (The User must be logged in to perform this action.)
- Show all Comments underneath a Post. Comments should display their commenter's name, the time it was posted, and the body of the Comment.
Goal: Add a Commenting System
- Convert the orderByDesc( "createdDate" ) to a scope called latest.
- Hide the implementation detail of userId when creating a Post by utilizing the posts relationship on User.
- Remove the cbsecurity check by constraining the Posts queries to the logged in user's posts using the posts relationship.
Goal: Make existing code cleaner, more readable, and more expressive using Scopes and Relationships
We Have a Problem...
- Ensure you have at least 10 posts and that at least one of your posts has at least 5 comments in order to see the N+1 problem and the fix.
- Install cbdebugger.
- Load the posts.index view and check out the cbdebugger view. Notice that we are executing a bunch of queries for our single page.
- Eager load the author relationship for our posts.index route.
- Eager load the commenter relationship for the posts.show route.
Goal: Solve the N+1 problem with Eager Loading
- Create a migration to add a tags table. Populate it with some pre-made tags.
- Create a Tag entity.
- Create a migration for the posts_tags pivot table between posts and tags
- Show a multiple select field on the posts.new form with all the tags.
- Validate and sync tags when creating the new Post.
- Show associated tags on the posts.index view.
- Show associated tags on the posts.show view.
- Show a multiple select field on the posts.edit form with all the tags. The currently associated tags should be pre-selected.
- Validate and sync tags when updating the Post.
- Make sure to eager load the tags on the posts.index view.
Goal: Allow adding tags to posts
(Usage in an APIs)
- Create a migration for a likes table. This is our pivot table between users and posts.
- Create an entity for a Like. Define the necessary relationships between Like, Post, and User.
- Create a route, handler, and action to save a User's like of a Post. This endpoint should return a memento of the Like entity with a 201 Created status code.
- Add a route and action to remove a User's like of a Post. This endpoint should return nothing with a 204 No Content status code.
- Add a thumbs up "Like" button to the bottom of the posts.show page. The button should show selected if the logged in user has liked the post.
- Wire up the button to hit the correct API endpoint when clicked.
Goal: Allow async liking of posts
- Replace eager loading the author with an authorName subselect on posts.index.
- Show the total number of comments for each post on the posts.index page.
- Show the total number of comments on the posts.show page in the Comments header.
- Show the number of likes for each post on the posts.index page.
- Show the number of likes on the like button on the posts.show page.
Goal: Reduce queries with subselects and relationship counts
Debugging with Quick
Debugging with Quick
Debugging with Quick
Debugging with Quick
Testing with Quick
- Integration Testing
- Testing Database
- Automatic Migrations and Resets
- Running Tests in Transactions
- Factories vs Fixtures
- Create a test database.
- Configure your application to run tests with the test database as the default datasource.
- Create a failing test case for visiting an existing author profile page. The following expectations should be met:
- It should be reached by visiting /authors/:authorID.
- It should show only the posts written by that author.
- When working TDD, try to only do the least amount of work needed to make the next different error appear. Try to guess the next error you will see before re-running the test.
- Once the test is passing, look for opportunities to refactor.
- Fill out the new author-profiles/show view.
- Link the author names from the posts.index and posts.show pages to the new author profile pages.
Goal: Utilize TDD to create an Author Profile page
- Backfill a test around the posts.index route.
- Add a failing test showing that posts with a scheduled date in the future do not appear on the page. Let this drive the implementation.
- Add the scheduled publishing feature.
- Now that your test is passing, you can refactor.
- Add a failing test showing that unpublished posts route to the 404 page when trying to view them directly.
- Implement this feature using TDD.
- Add the new field to your posts.new and posts.edit forms.
- Capture the optional published date in your handler.
- Verify it all works as expected in your app.
Goal: Add the ability to schedule posts to publish in the future using TDD
Up and Running with Quick
By Eric Peterson