Decouple Your Models with Form Objects

Video in TIB AV-Portal: Decouple Your Models with Form Objects

Formal Metadata

Decouple Your Models with Form Objects
Title of Series
Part Number
Number of Parts
CC Attribution - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this license.
Release Date

Content Metadata

Subject Area
Forms are a crucial part of every app and Rails has good defaults for building them—unless you need something complicated. Maybe you want a multi-step wizard? Or maybe you'd like to pluck attributes from any model? Validation becomes a pain point. So you introduce a state machine, or nest your models, or do some other calisthenic to get everything working. Thankfully there's a better way! This talk takes a complicated wizard and converts it into a few simple form objects—it's a deep dive on decoupling models and how you can leverage Trailblazer's Reform gem to make it even easier.
Mathematics Computer animation Software Projective plane Archaeological field survey Client (computing) Open set Cartesian coordinate system Social class
Default (computer science) Context awareness Information Multiplication sign Variance Bit Inverse element Mathematical model Mathematical model Field (computer science) Data model Latent heat Process (computing) Computer animation Personal digital assistant Hacker (term) Computer configuration Network topology Statement (computer science) Address space
Multiplication Computer animation Validity (statistics) Computer configuration Single-precision floating-point format Finite-state machine Mathematical model Mathematical model Compilation album Hand fan
Presentation of a group Computer animation Validity (statistics) Logic Computer configuration Multiplication sign View (database) Database Mereology Mathematical model Mathematical model Spacetime
Standard deviation Real number Insertion loss Database Distance Mathematical model Mathematical model Power (physics) Attribute grammar Word Exterior algebra Computer animation Object (grammar) Row (database)
Time zone Coefficient of determination Service (economics) Pay television Computer animation Set (mathematics) Client (computing) Cartesian coordinate system Address space Number Formal language
Goodness of fit Exterior algebra Matching (graph theory) Computer animation Validity (statistics) Object (grammar) Quicksort Mathematical model Rule of inference Mathematical model Gradient descent Attribute grammar
Point (geometry) Group action Presentation of a group Divisor Euler angles State of matter View (database) Translation (relic) Parameter (computer programming) Mathematical model Mathematical model Field (computer science) Number Attribute grammar Mathematics Different (Kate Ryan album) Electronic visual display Damping Control theory Error message Social class Area Standard deviation Validity (statistics) Inheritance (object-oriented programming) Block (periodic table) Interactive television Database transaction Database Subject indexing Computer animation Personal digital assistant Logic output Speech synthesis Object (grammar) Row (database)
Trail Service (economics) Computer animation Code Connectivity (graph theory) Bit Object (grammar) Mereology
Trail Functional (mathematics) Digital electronics Parameter (computer programming) Information privacy Mathematical model Mathematical model Field (computer science) Number Attribute grammar Medical imaging Mathematics Different (Kate Ryan album) Forest Flag Control theory Code refactoring Error message Rotation Validity (statistics) Block (periodic table) Forcing (mathematics) Database System call Category of being Type theory Message passing Computer animation Uniformer Raum Logic Personal digital assistant Object (grammar)
Array data structure Computer animation Network topology Control theory Object (grammar) Mountain pass Mathematical model
Area Default (computer science) Group action Inheritance (object-oriented programming) Multiplication sign Execution unit Mathematical model Field (computer science) Category of being Protein folding Computer animation Bit rate Flag Object (grammar)
Performance appraisal Pairwise comparison Computer animation Validity (statistics) Surface Object (grammar) System call Social class
Computer animation Computer configuration Code 1 (number) Right angle Control theory Bit Parameter (computer programming) Mathematical model Address space
Scripting language Group action Validity (statistics) Java applet Database Mereology Information privacy Field (computer science) Goodness of fit Urinary bladder Computer animation Logic Object (grammar) Address space Partial derivative Social class Row (database)
Module (mathematics) Time zone Validity (statistics) Multiplication sign Database Information privacy Mathematical model Mathematical model Field (computer science) Attribute grammar Category of being Computer animation Hash function Control theory Object (grammar) Figurate number Row (database) Social class
Group action Mobile app Validity (statistics) INTEGRAL View (database) Tap (transformer) Bit Line (geometry) Client (computing) Mathematical model Mathematical model System call Data model Computer animation Bit rate Logic Order (biology) output Software testing Pattern language Error message Row (database)
Revision control Point (geometry) Validity (statistics) Software developer Planning Tableau Cartesian coordinate system System call Mathematical model
this is a you have so I work at an agency called industrial more base of Ottawa it might be
the only Ottawa down that's not working for shopify at rails confident no I but were agency in we work closely with clients and the software is consistently evolving as a working on and it's a nice way of saying that class in their mind a lot which is totally fine but the challenge is finding ways of designing software that's open and flexible the change so I recently finished a project that was a big survey it was a lot of forms so the whole application with a form and before I start I wanna come up with the way that would be adaptable because the survey wasn't really set in stone so to be new questions to add all questions to remove the happened the user would go down from 1 form to the next was shipping so is the
challenge if you data model matches your form this is an easy problem rails is excellent defaults for creating a form that matches a data model the if you need to nest model the mean using accepts nested actually for and it's 1 of those things it's a little bit magical and I don't quite know how would what's happening there but once a form so to get a bit complicated yet resort hackers if statements in models of a validations amusing get a bit really so it's difficult understand context what's happening and change it becomes more difficult so I trees will find good ways to solve this problem for a long time and there are countless ways of doing it but a lotta depends on your specific use cases and requirements but for example you can store
fields the session that's a very good option in the city of a wizard where the user fills in information in their name the you know the address and then you store already in the session and the at each step and the process is done and savory thing to the inverse of the variance others Dunkeld wicked which is really
counted it's cleanup single models into multiple steps and then you had conditional validation to model based on which step you're here on are the state machine which I'm not a huge fan of some the cornerstone of simple in the again really pretty quick and form it seems kind of like throwing a a flame thrower at a candle flame 10 or something
another option tried is to Nestor models that is really good talk a few years ago arose comp by any in the basic idea is you have a big model is but it up is nested chunks and validate each chunk separately school stuff and always after the
great but an hourly for me and the reason is that allow these options struggle because the model of trying to bend the presentation details they're trying to match the form to the database to make validation to make valid informed easier but to me models shouldn't care about presentation details and I can actually get why this happens it forms a kind in this weird space the part view the part model that both those things at the same time and we all know were taught not the business logic view but what's never said is not but he Logic Viewlogic into our models so let's not do it this is really
after only can do whatever we want of so if if if if the those previous options I mentioned uh I don't really like them so what what is a good option
so I really like form objects it's a good alternative the modeling gnostic in that all not all your data needs to live on 1 big model gets small models that are tightly focused and describe what you need for the form the the criminals this custom layers between you and your model and they take a few ways of writing them on the the roll-your-own I'm enemies of gem called reform and for the loss this is define it like
what is it answer but simply perform object distance an object that we pass into form for so this is so the standard way of of form words passing having a person Active Record model into into form for here was not a form object but the idea is the same than have to be direct model can be anything you want this is the real power behind form objects is that have been limited to Active Record models we can compose objects from any attribute in a database as a is was of the doors for some are really flexible designs so let's look at an example to make
things clear of really building a service where dog walking companies can sign up and manage their clients so it assigned then this is the onboarding wizard before they can use the application I consists of 3 forms of the 1st thing we ask for the name and phone number of the company on the 2nd
form we ask them to add in some addresses and they can add remove multiple addresses and find the settings panel we ask for the name the size of the company their subscription time-zone uh the language preference method of those so this was 3 forms and it seems deceptively simple but there's some challenges here so that the 1st form the challenges
nested data the the phone model is a child of company and so is there a better alternative than accepts batch of for
and 2nd former data data matches are a model of pretty closely exactly this form and I'm sort of wondering is uniform object this example of good alternative or not what are the advantages of doing that and the chance of the 3rd formant that data is scattered all over the place and I don't know if were receiving to company again and all these feel the required save each step as we go along each form and it's going validation difficulty we had about the the entire model say and we can imagine outside of this example there may be many more attributes on these models that have their own rules for validation perhaps their own forms of is descent that's a simple example for the the purpose of this talk but you you know you can be built forms things get complicated quick OK bill the
first one and then show you how to write this and you know a form object is that with tools arils gives us and the role of the factor that with reform and then will compare afterwards so this your standard
rails controller are nothing too exciting here the only difference is the instance variable for for our view is the company formed on as for the great action were passing in some company parameters and a strong parameters and the attitudes are a name and number and even though number is nested we don't have to remember what this indexes for strong parameters of it doesn't matter in this case the and this is the form you of being simple form here but form for works great to in and this was passing a company form so we have a name for a company a number for phone and these form inputs a flat there's no nesting happening here at all and no need for a form field block even though the phones nested under company the so it's make form object is making class we include active model model which would was validation translations elastically object that's very close enough to record model and we do that by defining some attributes number and we define those attributes were the gonna go to watch the states in this case a new company in a nested company from the next biennium validation of this is the standard presence validation you get fancy here with some rejects on the phone number and all kinds of stuff always going keep it simple for this presentation and the next this points to a a method and the purpose of this validation method is to use to display errors validation errors so rails uses it except nested actions for display nested error messages so if we can define this method any nested models are like a phone model here would fail validation but the error messages would show up because they're the nested the company and the other the bubbled up to the parents so we do we write this method here display areas at all and that's all it does this bubble that error messages from from child relationships up to the pack and speaking which we to that so this method will now act like a company model companies can be apparent in this case and scoop points the company control in the same way that the company model next we have to define our own save method that's to that so how this works is what we call C it's gonna run to the validations if it's not valid it's gonna bubble upper error messages if it is we create transaction and then in that sit on everything is a bang methods so if anything here fails but it's can be rolled back and interactions in the database and there's no way for the controller to infer the idea of the company I really need that we redirect to the next form are so it is great that we see the great the company and the method the risk pocket that form object is with the delegates and better form object so not too difficult to write is really close to the rails way are controllers don't change much and it's nice way to do it the tricky thing about rowing your own easier on your own you have to write every little thing from scratch from saving the bubbling of validations and that the more complicated your form gets perhaps the more complicated logic e to figure out of these kind of base layer of using making do so there's a general they're called reform
and it's part of the Trail Blazers ecosystem may be as so
trailblazers is a talk on its own and little too deep down that rabbit hole but essentially it's a way of extending and NBC so the basic premises you organize your code not by Model-View-Controller but by concept and inside each concept or or component may be colored our service objects of operations and reform is 1 kind of operation the purpose of which is to build forms and the nice thing about trailblazer is you can use is just bits and pieces of it made use the whole thing and and i in the In the last a by building just use reform and it worked great so let's
refactor this form object that we just build but he's reform so assuming we've installed the genome of any to inherit from reform form Our refund doesn't know anything about wheels so will remove active model model it's a very similar idea to are excessive methods the chemical properties and they perform the exact same function defined writing track tributes the privacy have to define the model that this object is going to be talking to you and 1 differences in controller here are reforming the argument as written do the exact same thing by passing in a company so passing complained I into a form object and we hear this and we don't eat this delicate method anymore so all talking about validation in general but they stayed is that all this custom logic the rotational error messages bubbling up from nest models is the relevant it's taking care of forest so scary that and now because the pass in a new company from the controller but this method is already defined for us to confer with Indian companies and and snow on the form of working sound control announced that on the form object so relentlessly is is initializing the nested phone that and we have pass into the controllers Sony's Sweden defined here on form itself of because it's a nested object in the company reform has a specific way to define that type of relationship it's called collection it's a block and is called by the same name as the thing so folks circuits and then we define the properties assigned collection so number in this case and the 1 thing that's a change is a form of so we can all 1 keep this flag you that's kind of nice I we have induced fields for here and feels force matches to collections inside and for saving so we don't eat rare logic seems the database so will the something mildly different on controller to account for that a brief now is given a those are the strong parameters uh strong personal thing that we need to worry about that we set these attribution we define properties on form object and reform will ignore any and find parameters so we can just sit there with those and it was passed a company here the and the main difference here is how we see that a uniform object images validate before saving and instead will do this on a controller here so uh this call company formed that validate we pass and the parameters of the form gives us and we call seeds uh but something is wrong should look
like this but it looks like this maybe you had that experience before us a text that we do some
would be something like this we say to instantiate that that nested model on the controller and this will work but reform has its own method of reduce this occasion the it's called pre-populate and will define that conform object to do is add up the popular method to the collection work calling it builds phone we can call it whatever you want and does pay much which you expect a we grab a collection infections earn a raisin can call that building that new on it and tree like arrays and you and you phone for Notch phone
on it not display correctly think that can pretty good
I what thing we have to do is make sure their primary flag is set to true say this form I'll assume this left over from the previous example we'll deal with that but it's really easy only to do is add property primary said that so 1 issue though is for if you try to run a severe you test folds answered and the reason is that the reform makes no assumptions about this today it understands the parent object company we pass that into the form object but collections the different so you know we defined it reform seemed to know which model to post persist so any talent and you that was something called a popular so and I know what you might be thinking the popular years
populated areas what's going on here so it is the thing about it is the populated so our new unit actions the called manually with p populate they prepare the form for rendering the although this explain it and they can fill in us default fields into the form itself you want are popular is about creating and updating other called which every time we validate and the group prepare the form for validating and make sure that everything goes back into the rate model were supposed to go so at its most basic you can add a saying
to the collection of call populated and the it is passive class they want to map it to you know make sure that when you validates can persist to the phone class and tried about is that a such a form object so we use these evaluation they're we're going to go and that's it so as surface form at 2 ways to
write it and the 1st way we rolled around the 2nd way use reform here's a side-by-side comparison so
on the left is role our own reform on the right and it's pretty obvious that there is a lot less code to write for the reform option but for the controller I would say it's a bit of a wash of the roller your own on the left is a bit clearer and simpler because we just called save on it and wouldn't use strong parameters anymore a nice and side benefit it of us is going to the
next 1 amigo out quickly through the next ones I this form is adding a removing addresses and tapping on 1 model they have a small the controller using the edit and not
actions you're making a new address for our passing in our privacy credit company went to that for and recalling populate in a form we have a couple things going on so we have a fields for addresses here and it's kind partial called address form of incentive partial looks like this this just that lower fields for address the and has this hidden field a call destroy and that is going to market as like 1 or 0 like if you say destroy this thing it's chemicals 1 of us can be 0 the and there is however some custom acoustic helper here that with a little java script is going add a partial and this add more addresses when you click a button remove 1 week that so uniform object really carefully reform form we added a collection practices so destroyed is flagged as a virtual action you so it's it's not actually things going to the database our for pre-populated were doing very much the same thing we did before just making sure we have 1 you addressed to display on form and are popular urban have to write some custom lot logic to handle the adding new removal of addresses so privacy wrote populated empty a gas in a class at nearly writer own custom so others couple methods in here they're part of reforms the itself a fragment and collection so collection is going to iterate over all your addresses to be called company . addresses you may get 5 addresses back that's the collection of the fragment is each individual address and with the 90 and the popular will look through every record every fragment inside the collection so we see if we have an address we define as a local variable we try to find it on the collection to see if there's an idea of a fragment on there and if we find a fragment everything is good return on if it's empty we make 1 and if we see that on the fragment destroys at the 1 we delete that what we doing that fragment from the collection and then escape method will just skip to the next fragment and the last thing we need here the validation and what is this pump then in there and ran every now at a
removal of bladders here and the last form this example of this one's kind of tricky because the date is all over the place
so we have some stuff from companies some stuff from user account and with privacy safety companies so we don't want to necessarily of revalidate company again at least 1 valid every time we put something in the database and the this all this so
they're forming knows that there's no fields for anywhere in here it's flat another way to do it were listing actually it's wrapped caring but the data and we're going to find the data under control so the company and the user account and then already knew this form is on a those 3 models as a hash into a form object just like and therefore 1 object and we include this module called composition that comes with reform should will looks like so we define a company is apparent model they're going to safety you it that's really easy was at a properties and we just tell it which properties along with and we do that With this on attribute so timezones on company 1st name is on user Yedidia uh anywhere we may want rewrite have in class like each records ID we just given a new property name and widowed from the and because explicitly passing in objects into the form object with hashing using composition of referring to this figure out where everything is sitting too so there's no need to define populate of people leaders on this for and lastly used as data validations and so much so what are the advantages of doing
that so for data model
agnostic you no longer need to considerable on the view is setting up your data model 1 is kind of an ancillary benefit to this which is like small tightly focus more of these like giant making the models it the and not the not recommending but you could forgo having any validation in models whatsoever and instead royal line on the fact that the right data is getting to the right place based on the inputs the coming in and at the very least this means no conditional validation your in your models were valid in the form of the model itself so that a different way of thinking about it the this fall's rest we use such that 1 controller perform and this is following the rest actions very tightly focused and easy to understand and control is nothing too exciting and these are easy to test so test these form I would typically have like tap Ebara integration test are running through the whole wizard and and this the form logic themselves really nice with reform especially is passing hashing into the form and call valid on it and use make sure you gain the greater the rate error messages that way by going to set up the whole Active Record model to pass into the form just the date your past into the form and this was tests are nice to work with uh the fast and right this is also easy to extend and modify for client comes back and wants to change the order of a wizard or wants to change which actually you on which forms so we can do so without much effort and the last thing you can use them when you need to there's nothing wrong with using the rails the faults that makes sense to do so but as soon as the sort of get a bit more complicated this is a really good tool to have in in your back pocket and so Due to try I export see what it's like might really like it it's nice thing just incorporated into legacy apps it's a nice the pattern so they
few yes the question about the reform genome how stable of that I think it's a very stable from what I've been there when they working on it and it's very actively maintains unaware that point releases are going to be like a renowned said in version 2 uh and I think I think there's some big plans for 3 I'm not sure about that the so I'm not much but so far it's been really really nice to work with them and has been using the latest genome and been working really great yes the question was about going validation on the form and when you decide about just model it is just a form of and this is like a you have to make that call you know like when when is it crucial that your company has a name like doesn't have a name and the whole application blows up there and maybe make sense to have it on the model and if if you're say in the rails consular something and user developer are like FrameNet company for somebody many 1 make sure that the company at least has a name so because they by year-end isn't in this yeah you can 1 be careful with that stuff but in general for like the stuff that's not to to critical I just think about the the table thank you very much for coming the oecd . 0 if you treat her
from 8