Why is directly manipulating the Rails form params hash considered code smell? - html

I have a Rails form with a parent model and nested attributes for potentially multiple children of another model.
The child model has an attribute which is manipulated in logic as an array, but is serialized to a YAML string using the Rails built-in serialize method.
Within the form, I display each individual member of the array so that the user can selectively delete members.
The problem happens when the user destroys all members. The form will not pass any value for the param to the Rails controller and when the UPDATE action is called, it ignores the attribute since there is no key for it in the forms params hash. This is of course a known problem with things like checkboxes, so Rails automatically puts 2 checkbox HTML elements for each checkbox, one hidden that only processes if the checkbox is checked off.
I'm not dealing with checkboxes here but rather hidden input text fields.
The solution I've implemented is to manipulate the params hash directly in the UPDATE action of the controller, like this:
params[:series][:time_slots_attributes].each { |k,v| v[:exdates] ||= [] }
Is this considered code smell?
Should I instead add an extra hidden field that is disabled and only gets enabled when the user removes the last member? This solution works as well, but it seems clunky to me.

This is dealt with in the NestedAttributes module by allowing a "_destroy" parameter to trigger a destroy call for that particular nested attribute:
http://apidock.com/rails/ActiveRecord/NestedAttributes/ClassMethods/accepts_nested_attributes_for.
If you're not using nested attributes (which you probably should be, it's pretty neat in a lot of situations) then yes, you'll have to handroll something yourself, by working out which values should have been present and doing something special with those.

This is far from an exhaustive answer...but after thinking about this problem, one issue I can see is that if future forms are built that leverage the same UPDATE action, unexpected behavior will occur, which violates the principle of least surprise. If at a later time a second form is built which does not expect to change values for the exdates attribute (since it does not pass them), the UPDATE action will write an empty array into the attribute anyway.
I've decided to solve this issue by adding a single hidden form field with a true boolean value and later to check for this value before setting all time slot exdates to an empty array. This way, if a future developer creates a new form that leverages the UPDATE action of the series controller, they won't get the unexpected behavior of their exdates being set to empty arrays. If they want to process exdates in their form, they need to have the same hidden form field with a true value. This seemed like a simpler solution then adding a class and table for exdates, migration, and the AR associations and adding another layer of nested attributes so that I'd have not only a parent and children attributes, put a parent, children and grandchildren. This solution is a bit like the Rails hack for dealing with checkboxes with a second hidden checkbox field in the form.

Related

Angular Template Driven Form: Validate at least one Filled

I have a template driven form with multiple fields for searching in a table in angular. For this form, I would like to add a validation that checks that at least one input has been filled. It could then either enable the "search" button or display an error message if nothing has been put in. Either would work fine.
How can I add the said validation? I have looked up some similiar problems, but none would seem to work or fit the requirements.
Other Stack Overflow Post
Assuming your field are bound with [(ngModel)], you can simply disable to the search button if none are filled.
So if for instance your fields were a and b and each are bound to a field, you could disable the button based on conditions - [disabled] = "!a && !b" for as many fields as you have. Then, the search would only be enabled once a field had been filled in

CakePHP - refresh element/view cell using ajax

I'm trying to build a way to update a user profile one question at a time.
Essentially I want a div on my page that displays a form that lets the user submit the most important information, say firstname. When that has been filled out (success on the form) I want to refresh that div and show the second most important form, for say lastname, or if that is already filled in then birthday and so on.
Much like linkedin prompts you to add one more piece to your profile.
How would you do it?
My first thought was to use elements. But I need to fetch existing profile data to populate the form and how would the element get that data, abusing requestAction is not an option.
So I guess I in that case need to call a controller action that determines which element should be rendered, renders it to a variable and submits that (response->body) in json to the js that updates the page. Seems a bit .. unclean but should work.
Then we have view cells. They seem ideal for the task until I want to call them via ajax. That is not possible right?
So how would you go about to build something like that?
A form that needs to have the ability to be prepopulated with data if there is any and then refreshed automagically to display the form for the next piece of info needed.
View cells can't really be used in AJAX requests. This is not what they thought for.
The best thing you could do, if you want to keep the cell, is to make sure you followed SoC properly and put all your business logic into the model layer.
Now have a separate controller and action that is reachable from the outside throught a request (a cell is not) and return the data as JSON from there using the same code.
You could try to instantiate the cell in the controller action as well and send it's output. But honestly, I think that's a pretty fugly way of doing it.

How to instruct an element to update it's model from outside

In my polymer app, I have one element containing a list of items, and another element with the form to CRUD these items.
After inserting a new item from the form-element, how can I instruct the other element to re-pull the model data ? (and thus redraw the list items)
I'm using Firing custom events.
Suppose core-ajax is used for inserting a new item, on core-ajax response fire the event 'insert_done'.
List element should catch that event and get the items, this time with the new one in.
...
This is some general answer, but you can share some code for more specific answer.
Either lookup the list using a dom query and call an update method. Or, bind a variable that is used to notify the list of the change. Use an observer, in the list element, to execute the update code when the property value is changed by the form element.

how to avoid repetition of <select></select>?

Say, I have 50 input fields and in each field there is a dropdown list having options 1, 2, 3, .., 100.
Simply it can be done by inserting the long list of options in every input fields by commands.
Is there anyway by which we can write the full list only for one input field and refer it in the other input fields
If I'm understanding this question correctly this sounds like it would be a great case for using some server side logic like php or asp. A simple FOR loop would make it easy to maintain without adding the complexity / reliance on JavaScript that a client - side function brings into play.
You could use jQuery to append the options list to all dropdown lists with a certain class name in the $().ready() event handler.
JSFiddle Link

How to Control a Class Name class="fValidate['required']" in MooTools

I am using fValidator plugin for MooTools, and find necessary to control (depending on user selections) the required class it's used by the plugin.
The class uses a weird formatting which have never used before and for some reason MooTools can recognize it. It probably has something to do with escaping the square brackets and the single quotes.
I tried something like this, among other things, but no luck yet.
This is the code:
$("checkbox3").removeClass("fValidate\\[\\'required\\'\\]");
Are you looking to remove/add required elements to the validation? As it picks up all the elements at first you'd have to unregister them, remove the class and then re-register them.
Unfortunately it doesn't seem to have an unregister method by default so you'd have to monkey patch the script to add this, also as the register method doesn't parse class names you'd have to add a new method that does this. Finally you'd have to make the event that is added to the field for the blur in register a binding that you could re-use the binding to remove that event
It's quite an involved patch/rewrite of fValidator to achieve this and if possible I would look at another validation script -- such as form check which does allow you to un-register and re-register fields at run time (among a lot of other improvements).