19,785 Matching Annotations
  1. Feb 2021
    1. We are still open to the idea but the implementation should leverage the attributes API introduced in Rails 5.2 in Active Model.
    2. Is there are any possibility to speedup this pull-request to be merged?
    3. Fork rails, add github.com/georgebrock/rails as a remote, merge this branch into rails/4.0.2 (the tag), and then use your fork of Rails: gem 'rails', github: 'yourusername/rails'
    4. Sorry for the delay, life got in the way. I should have some time to pick this up again next week.
    5. I like this idea a lot. I have had problems too with having multi-parameters assignments depending so heavily on active record.
    6. If you take it to it's logical conclusion you'd only accept the correct types for boolean, integer, decimal, etc. columns, which is obviously crazy.
    7. I don't see too much gain in moving this to Action Controller beyond the "model layer shouldn't need to be aware of the format that's used to pass the data from the client to the server".
    1. More often than not, the expression ‘taken to its logical conclusion’ serves to point up the absurdity of a piece of reasoning we come across.
    2. I need a holiday to get over a holiday
    3. I wish there were no Mondays
    4. The golden standard I suppose is set by the rhyme: There is a hole in my bucket, dear Liza, dear Liza. Of course, fixing it requires the use of the bucket at some stage, and so the loop closes.
    1. The joint effort resulted in the creation of a freely-accessible database of over 29,000 scientific articles about the virus known as SARS-CoV-2, as well as correlated viruses in the broader coronavirus group.
    1. In object-oriented programming, information hiding (by way of nesting of types) reduces software development risk by shifting the code's dependency on an uncertain implementation (design decision) onto a well-defined interface. Clients of the interface perform operations purely through it so if the implementation changes, the clients do not have to change.
    2. The term encapsulation is often used interchangeably with information hiding. Not all agree on the distinctions between the two though; one may think of information hiding as being the principle and encapsulation being the technique. A software module hides information by encapsulating the information into a module or other construct which presents an interface.
    1. Encapsulation refers to the bundling of data with the methods that operate on that data.
    2. Does that make it so? Not for me. Were it simply a matter of words, I wouldn't write another word on the matter. But there are two distinct concepts behind these terms, concepts engendered separately and best understood separately.
    3. Authors rarely distinguish between the two and often directly claim they are the same.
    4. Like Humpty Dumpty proclaimed in Lewis Carroll's Through the Looking Glass, "When I use a word, it means just what I choose it to mean -- neither more nor less."
    1. Some people believed I argued that object orientation is bad simply because extends has problems, as if the two concepts are equivalent. That's certainly not what I thought I said, so let me clarify some meta-issues.

      first sighting: meta-issue 

    2. This column and last month's article are about design. Design, by nature, is a series of trade-offs. Every choice has a good and bad side, and you make your choice in the context of overall criteria defined by necessity. Good and bad are not absolutes, however. A good decision in one context might be bad in another.
    3. If you don't understand both sides of an issue, you cannot make an intelligent choice; in fact, if you don't understand all the ramifications of your actions, you're not designing at all. You're stumbling in the dark.
    4. Stating that some language feature or common programming idiom (like accessors) has problems is not the same thing as saying you should never use them under any circumstances.
    5. By the same token, marketing or political incentives often push design idioms
    6. companies want to promote what the technology can do, so they de-emphasize that the way in which you do it is less than ideal
    7. Consequently, you act irresponsibly when you adopt any programming practice simply because "that's the way you're supposed to do things."
    8. That's the whole point of an abstraction layer—to isolate your business logic from a subsystem's mechanics
    9. The JavaBean spec designers threw the getter/setter idiom into the picture because they thought it would be an easy way to quickly make a bean—something you can do while you're learning how to do it right. Unfortunately, nobody did that.Accessors were created solely as a way to tag certain properties so a UI-builder program or equivalent could identify them. You aren't supposed to call these methods yourself. They exist for an automated tool to use.
    10. You must modify the code surrounding each of those 1,000 calls to compensate for the change.
    11. My point is that you should not program blindly. You must understand the havoc a feature or idiom can wreak. In doing so, you're in a much better position to decide whether you should use that feature or idiom. Your choices should be both informed and pragmatic.
    12. The Java packages contain a lot of great code. But there are also parts of that code I'm sure the authors are embarrassed to admit they wrote.
    13. And just because a feature or idiom is commonly used does not mean you should use it either.
    14. Though getter/setter methods are commonplace in Java, they are not particularly object oriented (OO). In fact, they can damage your code's maintainability. Moreover, the presence of numerous getter and setter methods is a red flag that the program isn't necessarily well designed from an OO perspective.
    15. This article explains why you shouldn't use getters and setters (and when you can use them) and suggests a design methodology that will help you break out of the getter/setter mentality.
    1. In a rule-based system, a metarule is a rule governing the application of other rules.
    2. The modern sense of "an X about X" has given rise to concepts like "meta-cognition" (cognition about cognition), "meta-emotion" (emotion about emotion), "meta-discussion" (discussion about discussion), "meta-joke" (joke about jokes), and "metaprogramming" (writing programs that manipulate programs).
    1. If you think you’ve conveyed something but the other person hears something completely different, is that their fault or yours? 
    2. From my perspective the onus is on you to consider not just the words coming out of your mouth, but how they are received.
    3. Everyone has their own background and context that they overlay on top of what they hear. It’s our jobs as communicators to consider that perspective and to adjust the way we communicate accordingly. If we do, we stand a better chance of persuading them to agree with our point of view.
    1. People often hear what they think should be said, not the words that are actually spoken. This comes from the tendency of people to think faster than they talk. A listener makes assumptions about what they expect because their minds race ahead. This can be especially problematic when you misinterpret what your boss said. 
    2. How do you learn to listen more carefully? One good method is to repeat back what you think you heard. When the boss tells you something, don’t just say, “Okay.” Instead, repeat what you heard him tell you. This is called a briefback. Say, “So, you want me to . . .” If your brief back is not what the boss meant, the boss will let you know right then, and you won’t have wasted a lot of effort on the wrong thing. 
    1. Programming to interfaces is at the core of flexible structure.
    2. Rather than implement features you might need, you implement only the features you definitely need, but in a way that accommodates change. If you don't have this flexibility, parallel development simply isn't possible.
    3. At the core of parallel development, however, is the notion of flexibility. You have to write your code in such a way that you can incorporate newly discovered requirements into the existing code as painlessly as possible.
    4. many successful projects have proven that you can develop high-quality code more rapidly (and cost effectively) this way than with the traditional pipelined approach
    1. The more important point comes from a program design perspective. Here, "programming to an interface" means focusing your design on what the code is doing, not how it does it. This is a vital distinction that pushes your design towards correctness and flexibility.
    2. This is not correct. Or at least, it is not entirely correct.
    3. My understanding of "programming to an interface" is different than what the question or the other answers suggest. Which is not to say that my understanding is correct, or that the things in the other answers aren't good ideas, just that they're not what I think of when I hear that term.
    4. Programming to an interface means that when you are presented with some programming interface (be it a class library, a set of functions, a network protocol or anything else) that you keep to using only things guaranteed by the interface. You may have knowledge about the underlying implementation (you may have written it), but you should not ever use that knowledge.
    5. The problem with this is that it creates a strong coupling between your code and the implementation, exactly what the interface was supposed to prevent.
    6. Depending on the politics it might either mean that the implementation can no longer be changed, because that would break your code, or that your code is very fragile and keeps breaking on every upgrade or change of the underlying implementation.

      not quite sure how this is politics, but interesting example

    7. If the program was important enough, Microsoft might actually go ahead and add some hack to their implementation so the the program would continue to work, but the cost of that is increased complexity (with all the ensuing problems) of the Windows code. It also makes life extra-hard for the Wine people, because they try to implement the WinAPI as well, but they can only refer to the documentation for how to do this, which leads to many programs not working as they should because they (accidentally or intentionally) rely on some implementation detail.
    8. Abstract myself from the how it does and get focus on what to do.
    9. Say you have software to keep track of your grocery list. In the 80's, this software would work against a command line and some flat files on floppy disk. Then you got a UI. Then you maybe put the list in the database. Later on it maybe moved to the cloud or mobile phones or facebook integration. If you designed your code specifically around the implementation (floppy disks and command lines) you would be ill-prepared for changes. If you designed your code around the interface (manipulating a grocery list) then the implementation is free to change.
    10. It's more like providing an Employee object rather than the set of linked tables you use to store an Employee record. Or providing an interface to iterate through songs, and not caring if those songs are shuffled, or on a CD, or streaming from the internet. They're just a sequence of songs.
    1. which have recently become umbrella terms referring to any piece of quickly-consumed comedic or relatable content
    2. Remix occurs when the original meme is altered in some way, while mimicry occurs when the meme is recreated in a different fashion to the original.

      I don't even understand the difference (yet)

    1. The Chicago Manual of Style and the Associated Press (AP) both revised their formerly capitalized stylization of the word to lowercase "internet" in 2016.[3] The New York Times, which followed suit in adopting the lowercase style, said that such a change is common practice when "newly coined or unfamiliar terms" become part of the lexicon.
    2. The Oxford English Dictionary says that the global network is usually "the internet", but most of the American historical sources it cites use the capitalized form.
    3. Technical authors still also use the uncapitalized form in singular and plural (internets) forms to describe the interconnection of multiple individual networks.
    4. The spelling "internet" has become often used, as the word almost always refers to the global network; the generic sense of the word has become rare in non-technical writings.

      rare to see "internet" used to mean an internetwork in the general sense

    1. Proponents theorize that memes are a viral phenomenon that may evolve by natural selection in a manner analogous to that of biological evolution.
    1. Something that is implicit is inferred - it is suggested by the way it is said. Implicit meaning can be harder to figure out than explicit meaning.
    2. Something that is explicit is stated directly and is clear in meaning. Explicit meaning is the easiest to pick out from a text.
    1. The word home, for instance, has a denotation of “the place (such as a house or apartment) where a person lives,” but it may additionally have many connotations (such as “warmth,” “security,” or “childhood”) for some people.
    2. While each of these two words has several possible meanings, they are notably distinct from each other in all senses. Denotation is concerned with explicit meaning, and connotation tends to be concerned with implicit meaning.
    1. With the introduction of CPUs which ran faster than the original 4.77 MHz Intel 8088 used in the IBM Personal Computer, programs which relied on the CPU's frequency for timing were executing faster than intended. Games in particular were often rendered unplayable. To provide some compatibility, the "turbo" button was added. Engaging turbo mode slows the system down to a state compatible with original 8086/8088 chips.
    2. Contrary to what it suggests, the "turbo" button was intended to let a computer run slower than the speed for which it had been designed.

      I guess they called it that because it would be come across better than calling it a "slow" button!

    1. Some languages like Smalltalk and Ruby only allow access via object methods
    2. They claim that inheritance often breaks encapsulation, given that inheritance exposes a subclass to the details of its parent's implementation.
    3. Encapsulation is used to hide the values or state of a structured data object inside a class, preventing direct access to them by clients in a way that could expose hidden implementation details or violate state invariance maintained by the methods.
    1. you can do pairs.each_with_object({}) do |(multiparameter_name, value), attributes|
    2. values_with_empty_parameters.each_value.all?(&:nil?) This comment has been minimized. Show comment Hide comment Copy link Quote reply egilburg on Apr 9, 2015 Contributor you can do values_with_empty_parameters.values.none? [nil, nil].none? => true Pick your reaction egilburg on Apr 9, 2015 Contributor you can do values_with_empty_parameters.values.none? [nil, nil].none? => true
    3. @kirs can we leave the typecast API out for now? This will conflict with the work @sgrif want to do and it would maybe make harder to integrate.
    1. As I reported in #10, error keys get duplicated and we should namespace them. This code behaves right like AR::Base accept_nested_attributes
    1. class ConferencesController def create conference = Conference.new @conference_form = ConferenceForm.new(conference) @conference_form.submit(conference_params) if @conference_form.save redirect_to @conference_form, notice: "Conference: #{@conference_form.name} was successfully created." } else render :new end end end
    2. ActionForm also can accept ActiveModel::Model instances as a model.
    3. You can find a list of applications using this gem in this repository: https://github.com/m-Peter/nested-form-examples . All the examples are implemented in before/after pairs. The before is using the accepts_nested_attributes_for, while the after uses this gem to achieve the same functionality.
    1. This would be more useful if there was an easy way to actually compare the differences...

      This is how I did it:

      cd user-example
      diff -r -u10 before/ after/
      # then compare after/app/forms, which was only in after
      

      Linked to from https://hyp.is/5YyPAnFNEeu0Vv94pLaypA/github.com/railsgsoc/actionform

    1. My reasoning for not gemifying ActiveForm is that the custom not-rails-core logic is relatively small
    2. I've utilized as many Rails modules as I can to make maintenance a lot easier as I just have to update Rails and I get the updates for free. By utilizing Rails core modules, it's a really small library - there are only 10 methods in the Base module!
    3. while ActiveForm currently fits 99% of my use cases, I do sometimes make modifications based on the product requirements
    4. For now I feel ActiveForm is still a bit early to transition to a gem  as there are still things to improve and work out. One day I'll invest more time into making it extendable and release it as a gem. For now I feel it's an unnecessary complexity.

      If he's like most of us, though, this means it will never happen...

    5. I will continue to use form objects and push changes into the repo when I feel they are universally relevant and valuable.

      new tag?:

      • code that is universally relevant/valuable
      • non - _-specific logic
    6. we get the benefit of isolating request specific logic without cramming it into a ActiveRecord model that will be used in multiple controllers/actions

      request-specific logic

    7. The controllers feel very familiar to using ActiveRecord models
    8. if you name you instance variable form, then you can always just pass in params[:form]
    9. However, sometimes actions can't be rolled back and it is unfortunately unavoidable. For example, consider when we send emails during the call to process. If we send before saving a record and that record fails to save what do we do? We can't unsend that email.
    10. I typically save everything I can first, and then call the side-effects afterwards. If the side-effects fail I can handle them elsewhere and retry when necessary.
    11. Writing the uniqueness validations yourself is easy so I felt it was better to leave this up to the developer
    12. Why process, not save? This is entirely up to you. However, it's good to stay consistent across your team so there's no confusion. I began using save but found there are some cases for forms where you aren't saving anything, such as when you are just triggering a job or push-notification. I found using process fits more cases so that's what I use. This is also typically the only method that is public on my forms.

      process is a good name, but I think this is evidence that this object is not the form object itself, but a form processor (as I like to call it) or a "workflow" object (like https://github.com/gogogarrett/reform_example/blob/master/app/forms/workflows/user_workflow.rb), which wraps a form object.

    13. ActiveForm has the attribute allow-listing by default. Any attribute in the list will be allowed
    14. Any attribute in the list will be allowed, and any defined as attr_{accessor,reader,writer} will not be populated when passed in as params. This means we no longer need to use strong_params in the controllers because the form has a clear definition of what it expects and protects us by design.

      strong params not needed since form object handles that responsibility.

      That's the same opinion Nick took in Reform...

    15. I've been over the use case for form objects in this post on moving away from fat models but wanted to go into more detail on how and why I use them here. I really believe in the utility of these objects; their ability to abstract and isolate logic in a simple and effective manner is unmatched, IMO.
    16. The basic classification of a form object is a class that contains writable attributes, validations and logic to persist the attributes to ActiveRecord objects. These forms can also include other side-effects like background job triggers, emails, and push-notifications etc. The simplest way to understand the concept is to think of them as a representation of a controller action where all of the business logic that happens in that controller action is abstracted into a form object.

      This definition may be a bit too broad. Others (like Reform) define it to have smaller scope — only the part where it persists/validates attributes. The other side effects might be better to put in a different location, like the controller action, or a service/processor object that has a form object.

    1. it's just a shame that there's no online or split-screen multiplayer, which seems like a major oversight to us; local play between Switch system is possible, but could prove to be a logical nightmare.
    2. logical

      logistical?

    1. Игра лютая дрянь, MX unleashed лучше в 100 раз. Физики нет, трассы дрянь, трюки вырвиглазны. Я заплатил за игру 150 руб, она даже копейки не стоит.

      The game is fierce rubbish, MX unleashed is 100 times better. There is no physics, the tracks are rubbish, the tricks are torn out. I paid 150 rubles for the game, it doesn't even cost a penny.

    1. Did you by any chance ever finish/publish your solution for this?
    2. I do think it's a common pattern that should be solved, and I am probably going to try and solve it as a Gem as opposed to simply writing code that we use in our code base
    3. with ActiveForm-Rails, validations is the responsability of the form and not of the models. There is no need to synchronize errors from the form to the models and vice versa.

      But if you intend to save to a model after the form validates, then you can't escape the models' validations:

      either you check that the models pass their own validations ahead of time (like I want to do, and I think @mattheworiordan was wanting to do), or you have to accept that one of the following outcomes is possible/inevitable if the models' own validations fail:

      1. if you use object.save then it may silently fail to save
      2. if you use object.save then it will fail to save and raise an error

      Are either of those outcomes acceptable to you? To me, they seem not to be. Hence we must also check for / handle the models' validations. Hence we need a way to aggregate errors from both the form object (context-specific validations) and from the models (unconditional/invariant validations that should always be checked by the model), and present them to the user.

      What do you guys find to be the best way to accomplish that?

      I am interested to know what best practices you use / still use today after all these years. I keep finding myself running into this same problem/need, which is how I ended up looking for what the current options are for form objects today...

    4. I'd like to know specifically what you were aiming to achieve with this Gem as opposed to simply using https://github.com/apotonick/reform? I am happy to help contribute, but equally if there is a gem out there that already does the job well, I'd like to know why we shouldn't just use that.
    5. Like all best practices, I think the way you will resolve a problem will depend of the application you are doing.
    6. DSLs can be problematic for the user since the user has to manage state (e.g. am I supposed to call valid? first or update_attributes?). This is exactly why the #validate is the only method to change state in Reform.
    7. The reason Reform does updating attributes and validation in the same step is because I wanna reduce public methods. This is to save users from having to remember state.

      I see what he means, but what would you call this (tag)? "have to remember state"? maybe "have to remember" is close enough

      Or maybe order is important / do things in the right order is all we need to describe the problem/need.

    8. I agre with your concern. I realy prefer to do this : form.assign_attributes(hash) if form.valid? my_service.update(form) #render something else #render somthing else end It looks more like a normal controller.
    9. Furthermore, you call #sync_and_validate_with and #then_validate. When I read this line I understand than it do the validation two times.
    10. My only concern with this approach is that if someone calls #valid? on the form object afterwards, it would under the hood currently delete the existing errors on the form object and revalidate. The could have unexpected side effects where the errors added by the models passed in or the service called will be lost.
    11. My concern with this approach is still that it's somewhat brittle with the current implementation of valid? because whilst valid? appears to be a predicate and should have no side effects, this is not the case and could remove the errors applied by one of the steps above.
    12. I find reform's implementation a bit too complicated too (lots of layers of abstraction, including going through the representable gem for a lot of things)
    13. I made this gem because I tried reform and I found some bugs. I started to contribute but there is some things I don't like in reform.
    14. but there is some things I don't like in reform
    15. Another problem I found with Reform is the synchronisation with models. The object you passed in argument to reform does not have the same value than the form.
    16. If you compare the code of Reform and the code of ActiveForm-Rails, I think the last is more simple and clear for a behavior similar (or better).
    17. Finally, I really do something simple and I find the reform's implementation is a little bit too complicated for what I want. I think my code (and yours) is simple.
    18. I close the issue but we can continue the discussion.

      closing does not necessarily imply end of discussion

    19. Trust me, I thought a lot about #validate and its semantics, and I am gonna make it even more "SRP" by making Form#errors and #valid? semi-public. All that happens via #validate reducing the possible wrong usage for users.
    20. About #validate which fill attributes of the form, I think it's a problem of architecture and clarity. If you respect the Single Responsabilty Principle, you must to have two methods. This is wrong. SRP means your class does exactly one thing, which is reflected in a single public method. The more methods you expose, the less SRP you go.
    21. I apologize for the slow development of Reform after the "explosion" when I released it initially. The reason for this is I changed jobs and didn't use Reform (yet).
    22. I meant to say after I published Reform I changed jobs (unrelated to Reform) and in the new project, we don't use Reform, yet
    23. Thanks for all your patches and ideas so far!
    24. I like your API here much better than reform's API.
    25. reform conflates these two responsibilities into a single validate method
    26. About #validate which fill attributes of the form, I think it's a problem of architecture and clarity. If you respect the Single Responsabilty Principle, you must to have two methods. The validate method do two thing really different.
    27. I have developed a simple pattern that copies errors from the model or the service into the form object so that the view can still use those errors
    28. commented

    Tags

    Annotators

    URL

    1. def self.attribute(name, type = ActiveModel::Type::Value.new, **options) super attribute_type = attribute_types[name.to_s] # Add the ? method for boolean attributes alias_boolean(name) if attribute_type.is_a?(ActiveModel::Type::Boolean) # store date attribute names so we can merge the params during # initialization date_attributes << name if attribute_type.class.in?(DATE_TYPES) end
    2. merge_date_and_time_params
    3. dealias_params(params_hash)
    4. *initialize* also supports passing resources (also attributes if you would # like to) manually
    5. An additional usecase is where we would like to update multiple records
    6. This can be useful in cases like multistep registration. Previously in # rails we used to stick all of the validations in the class and then we're # stuck validating them all everytime
    7. Some developers found work arounds by using virtual attributes to # skip validators
    1. Hopscotch
    2. simplify complex business logic
    3. Top level architecture
    4. You can optionally compose the steps manually (great for reuse) and just make use of the Runner#call method.
    5. class UsersController < ApplicationController def create success = -> (response, time) { redirect_to root_path, notice: "#{response} - at: #{time}" } failure = -> { render :new } Workflow::CreateUser.call(params[:name], success: success, failure: failure) end end
    6. While this example could work, we're already duplicating code and things could easily get out of sync with the previous Signup runner.
    7. What does this mean for our runner? They get simpler and allow for quick reuse! Let's see.
    8. Let's assume that something in the system has to change (as it rarely does..), and we need to add a new step to the process to the runner
    1. Please buy my book to support the development and learn everything about Reform
    2. By explicitly defining the form layout using ::property there is no more need for protecting from unwanted input. strong_parameter or attr_accessible become obsolete. Reform will simply ignore undefined incoming parameters.
    3. Great thanks to Blake Education for giving us the freedom and time to develop this project in 2013 while working on their project.
    1. Launched in 2008, our breakthrough reading app, Reading Eggs, has been used by over 3.4 million users in 169 countries.

      Have Reading Eggs for kids. First time I had learned anything about the company behind it.

      Here: https://hyp.is/G85jmnChEeuRiUMfGc0Brg/github.com/trailblazer/reform

    1. I found the code a little bit complicated. Why to instanciate instance variables in this class instead to do a hash that could be used like this form.models[:first_model]; form.model[:second_model]?
    2. This looks like a really nice patch. (I haven't tried it out yet though.) Any reason we shouldn't merge this in? I really like all the new tests you added in test/active_record_composition_test.rb
    1. Set your models free from the accepts_nested_attributes_for helper. Active Form provides an object-oriented approach to represent your forms by building a form object, rather than relying on Active Record internals for doing this.
    2. @conference_form.submit(conference_params)

      Surprised they called it submit, since that could imply that you're triggering an action called submit.

      They use other verbs to describe this:

      • sync
      • populate
      • write

      Analogous to Reform's sync / sync_models method.

      Actually, the name makes a lot of sense when you see it in context:

          @conference_form = ConferenceForm.new(conference)
          @conference_form.submit(conference_params)
      
          if @conference_form.save
      
    3. initialize(model) accepts an instance of the model that the form represents.

      By designing this so there is a main model, it isn't as flexible as Reform's "Composition" module that lets you compose it in any way you want, including having as many as you want top-level "main" modules that your form is comprised of.

    4. Special thanks to the owners of the great gems that inspired this work: Nick Sutterer - creator of reform Nathan Van der Auwera - creator of cocoon
    1. More and more, Im seeing this "retro graphics" (aka - lazy cash in.) money grab titles that are completely broken or absolutely terrible.. and they're RAPIDLY flooding the Switch like flies to horse dung. With no real reliable independent reviews of Indie titles available (Even MetaCritic is blank for at LEAST 70% of these indie garbage games..) players are left with no recourse but to flush hard earned cash on what is essentially a non-refundable gamble.
    1. Finally, you can use fields_for in order to create/edit associated fields and the suffix _list (like profile_list below) to choose an existing associated record.
    2. Seems similar to Reform, but simpler, plays nicely with Rails

    3. @user_form = UserForm.new(User.find(params[:id])) # you need to load the record being edited
    4. # Use relationship's name followed by "__" plus attribute's name # to validate has_one and belongs_to associations validates :name, :address__street, :company__name, presence: true
    1. There is nothing wrong with accepts_nested_attributes_for. This is what you should use in your typical case. My post describes a non-typical case. ContactListForm is not an ActiveRecord object, it is an object that includes ActiveModel::Model, which does not support accepts_nested_attributes_for.
    2. If you include ActiveModel::Validations you can write the same validators as you would with ActiveRecord. However, in this case, our form is just a collection of Contact objects, which are ActiveRecord and have their own validations. When I save the ContactListForm, it attempts to save all the contacts. In doing so, each contact has its error_messages available.
    3. Of course our object doesn't have any contacts yet, so our controller will need to make sure that the form has at least one fields_for block to render by giving it one on initialization