Converting nested attributes from string to numeric - ruby-on-rails-4.2

I have a GALLERY model containing nested SLIDE attributes. Some of my attributes are enum values. Without intervention my params hash receives the enum values as "0" or "1". This results in an error e.g. '0' is not a valid gallery type.
Here is an example of my params hash:
{"name"=>"Video quis terrax", "gallery_type"=>"0",
"slides_attributes"=>{"0"=>{"id"=>"2", "order"=>"0",
"slide_type"=>"0", "image_cache"=>"", "embedded_url"=>"",
"_destroy"=>"0"},
"1441761800650"=>{"order"=>"0", "slide_type"=>"0",
"image"=>#,
#original_filename="large_veh_photo.jpg",
#content_type="image/jpeg", #headers="Content-Disposition: form-data;
name=\"gallery[slides_attributes][1441761800650][image]\";
filename=\"large_veh2.jpg\"\r\nContent-Type: image/jpeg\r\n">,
"image_cache"=>"", "embedded_url"=>"", "thumb_text"=>"2nd Image",
"_destroy"=>"0"},
"1441761824429"=>{"order"=>"0", "slide_type"=>"0",
"image_cache"=>"", "embedded_url"=>"", "_destroy"=>"0"}}}
You will notice that there are 3 slides in this example. The first one is identified by "0", the 2nd one by "1441761800650" and the 3rd one by "1441761824429". The first slide has already been saved. The 2nd one is a new slide and the 3rd one has no details filled in. These long number are automatically allocated by Rails in the view.
How can I change the "order" and "slide_type" attributes to numeric values before the controller attempts to do
#gallery.update(gallery_params)
Do I have any control over the random numbers assigned to my slides in the view?

You need to clean up the params in the controller. You should be able to do something like this:
Class SomeController < ActionController
before_filter: clean_gallery_params
def clean_gallery_params
params[:slides_attributes].each do |slide_attribute|
params[:slides_attributes][slide_attribute][:order] = params[:slides_attributes][slide_attribute][:order].to_i
params[:slides_attributes][slide_attribute][:slide_type] = params[:slides_attributes][slide_attribute][:slide_type].to_i
end
end
...

Related

Terraform variable user inputs long key value pair

I am using a 3rd party app called Morpheus (not a fan of it but its enforced)
I built some modules which are easy enough to request the end user selecting a "Catalog item" to be provisioned and asked for name, and drop down list with ex: instance size, etc.
My issue is thou, I need the user to enter in 1 long string of key value pair to be added to an attribute.
for example
parameters = [var.params]
and the end user inputs in the text field
"example1": "value1", "example2": "value2"
but of course this does not work. I tried {"example1": "value1", "example2": "value2"} and
parameters = [jsondecode(var.params)]
also does not work. Stuck on what / how to request end user to enter in the values in a specific format. The txt box is 1 liner btw :(, hence why im not a fan of morpheus but whatev's

Multivalued Fields in XPages

I have 3 fields with multivalue. I need this field values to be shown line by line in ViewPanel. But I do not know how to do it. For example
FIELD1 Values: Bursa;Adana;Konya (String)
FIELD2 Values: 14;15;16 (Numeric)
FIELD3 Values: 201,55 ; 155,85 ; 69,96 (Numeric)
What I need to see in a viewPanel that FIELD1 values should be main category then I need see It's value in below. I have created a view but Every value is shown as string seperated vie comma(","). I have no idea how to do it. Please dinf the screenshot below.
VIEW PANEL with Categorized MultiValue Column
->Bursa
14 201,55
->Adana
15 155,85
->Konya
16 69,96
Short answer: you don’t use a ViewPanel
Long answer: use a repeat control with the View as data source. Then you have access to each viewEntry and construct multiple HTML lines inside the body of the repeat. You might entertain a second repeat control inside. I would use either a JSON object or an instance of a Java class to rearrange the viewcolumn objects into something easier to iterate.
function columnsToArray(viewEntry) {
var result = [];
// loop through the values
// to build something like
// var linearem = {label1: val1, label2: var2}
result.push(linearem);
// end loop
return result;
}
Pseudo code only
Repeat will work, as suggested by Stephan. You can make things a bit easier to prepare your data in the view column value:
#Implode( #Text( field ); "<br>")
and make sure the value is treated as HTML by htmlFilter property of the column https://www.ibm.com/support/knowledgecenter/en/SSVRGU_9.0.1/user/wpd_controls_pref_htmlfilter.html.

Web2Py list:reference table, Load and set data

Maybe I'm missing something absurd, I'm not seeing, but this is my first app to study web2py.
I am unable to enter the data in Table Movies, which has fields related to other tables.
The list is loaded, but it is not registered in Movies registration.
Under the codes and the results.
db.py
Movie = db.define_table('movies',
Field('title','string', label = 'Title'),
Field('date_release','integer', label = 'Date Release'),
Field('duraction','integer', label = 'Duraction'),
Field('category','string','list:reference categories', label = 'Category'),
Field('actor','list:reference actors', label = 'Actor'),
Field('director','list:reference directors', label = 'Diretor'),
)
Category = db.define_table('categories',
Field('title','string', label = 'Title'),
)
validators.py
Movie.title.requires = [IS_NOT_EMPTY(), IS_NOT_IN_DB(db, 'movies.title')]
Movie.category.requires = IS_IN_DB(db, 'categories.title')
Movie.director.requires = IS_IN_DB(db, 'directors.name')
Movie.actor.requires = IS_IN_DB(db, 'actors.name')
Movie.duraction.requires = IS_INT_IN_RANGE(0, 1000)
Category.title.requires = IS_NOT_EMPTY()
movie.py
def add():
form = SQLFORM(Movie)
if form.process().accepted:
response.flash = "Successful! New movie added!"
redirect(URL('add'))
elif form.errors:
response.flash = 'Error'
else:
response.flash = 'Form, set data'
return dict(form = form)
List Load another tables - ok:
The items of list not record in DB:
The widgets displayed in the form are based on the IS_IN_DB field validators you have specified, and there are three problems with the way you have coded them.
First, list:reference fields, like standard reference type fields, store the record IDs of the records they reference -- they do not store values of other fields within the referenced records. So, the second argument to the IS_IN_DB validator should always be the ID field (e.g., categories.id).
Second, although the field will store record IDs, you want the form widget to show some other more descriptive representation of each record, so you should specify the "label" argument of the IS_IN_DB validator (e.g., label='%(title)s').
Third, list:reference fields allow for multiple selections, so you must set the "multiple" argument of the IS_IN_DB validator to True. This will result in a multi-select widget in the form.
So, the resulting validator should look like this:
Movie.category.requires = IS_IN_DB(db, 'categories.id', label='%(title)s', multiple=True)
The above will allow multiple db.categories IDs to be selected, though the form widget will display category titles rather than the actual IDs.
Now, all of the above can be made much easier if you instead define the referenced tables before the db.movies table and specify a format argument for each table:
Category = db.define_table('categories',
Field('title','string', label = 'Title'),
format='%(title)s')
Movie = db.define_table('movies',
...,
Field('category', 'list:reference categories', label = 'Category'),
...)
With the above code, there is no need to explicitly specify the IS_IN_DB validator at all, as the db.movies.category field will automatically get a default validator exactly like the one specified above (the format attribute of the db.categories table is used as the label argument).
You might want to read the documentation on list:reference fields and the IS_IN_DB validator.
As an aside, you might consider specifying your field validators within the table definitions (via the requires argument to Field()), as this is more concise, keeps all schema-related details in one place, and eliminates the need to read and execute an additional model file on every request.

Web2py: Incorrect row when representing a referenced field

It's rare that I find an issue that hasn't already be answered but I've been searching for this for 3 days and haven't found anything yet.
I'm aiming to create a page for inputing records in a 'spreadsheet' like format. I've used inline editing in SQLFORM.grid from this slice.
The problem I'm having is that when one of the fields is a reference to another table, the row being use in the lambda function is taking the row of the reference table rather than the row in the grid.
Here is an example:
Model
db.define_table('people',
Field('name', 'string'),
format = '%(name)s',
)
db.define_table('animals',
Field('name', 'string'),
Field('pet_owner', 'reference people'),
format = '%(name)s',
)
Controller
def index():
#process submitted form
if len(request.post_vars) > 0:
print request.post_vars
for key, value in request.post_vars.iteritems():
(field_name,sep,row_id) = key.partition('_row_')
if row_id:
db(db.animals.id == row_id).update(**{field_name:value})
db.animals.name.represent = lambda value,row: SQLFORM.widgets.string.widget(db.animals.pet_owner,value, **{'_name':'name_row_%s' % row.id})
db.animals.pet_owner.represent = lambda value,row: SQLFORM.widgets.options.widget(db.animals.pet_owner,value, **{'_name':'pet_owner_row_%s' % row.id})
grid = SQLFORM.grid(db.animals,
selectable= lambda ids : redirect(URL('animals',vars=request._get_vars)),
)
grid.elements(_type='checkbox',_name='records',replace=None) #remove selectable's checkboxes
return dict(grid=grid)
At first it appears that the grid is working correctly. However, when inspecting the drop-downs for the reference fields, if two consecutive rows have the same value (e.g. two animals with the same owner) the same row is used in the name (pet_owner_row_1) which means that the value being passed to process the submitted form is not an integer (e.g. 3) but as the integers separated by pipes (e.g. '|3|3|').
I've confirmed that this is where the issue is by changing the represent to
db.animals.pet_owner.represent = lambda value,row: row
which shows the exact same row data for different animals.
Here is an image showing the inspector on the form items: http://i.stack.imgur.com/oFtF8.png
How can I get the row id of the grid's row rather than the id of the reference?
Any help is greatly appreciated!
This is a bug that has recently been fixed in the master branch but not released yet. In the meantime, a workaround is to temporarily change the field to an integer type:
db.animals.pet_owner.type = 'integer'
db.animals.pet_owner.represent = lambda value,row: SQLFORM.widgets.options.widget(
db.animals.pet_owner,value, **{'_name':'pet_owner_row_%s' % row.id})

Binding an edit box within a custom control to a form field programatically

I have a notes form with a series of fields such as city_1, city_2, city_3 etc.
I have an XPage and on that XPage I have a repeat.
The repeat is based on an array with ten values 1 - 10
var repArray = new Array() ;
for (var i=1;i<=10;i++) {
repArray.push(i) ;
}
return(repArray) ;
Within the repeat I have a custom control which is used to surface the fields city_1 through city_10
The repeat has a custom property docdatasource which is passed in
It also has a string custom property called cityFieldName which is computed using the repeat
collection name so that in the first repeat row it is city_1 and in the second it is city_2 etc..
The editable text field on the custom control is bound using the EL formula
compositeData.docdatasource[compositeData.cityFieldName]
This works fine but each time I add new fields I have to remember to create a new custom property and then a reference to it on the parent page.
I would like to be able to simply compute the data binding such as
compositeData.docdatasource['city_' + indexvar]
where indexvar is a variable representing the current row number.
Is this possible ? I have read that you cannot use '+' in Expression Language.
First: you wouldn't need an array for a counter. Just 10 would do (the number) - repeats 10 times too. But you could build an array of arrays:
var repArray = [];
for (var i=1;i<=10;i++) {
repArray.push(["city","street","zip","country","planet"]) ;
}
return repArray;
then you should be able to use
#{datasource.indexvar[0]}
to bind city,
#{datasource.indexvar[1]}
to bind street. etc.
Carries a little the danger of messing with the sequence of the array, if that's a concern you would need to dig deeper in using an Object here.
compute to javascript and use something like
var viewnam = "#{" + (compositeData.searchVar )+ "}"
return viewnam
make sure this is computed on page load in the custom control
I was never able to do the addition within EL but I have been very successful with simply computing the field names outside the custom control and then passing those values into the custom control.
I can send you some working code if you wish from a presentation I gave.

Resources