I need to store the bellow parameter into a table:
[{"id":"1","name":"Cheese and red deans","amount":2,"price":"0.65"},{"id":"2","name":"Pork, cheese and red beans","amount":2,"price":"0.85"},{"id":"3","name":"Soda","amount":1,"price":"0.65"}]
The controller's code is this (I'm using ActiveController):
#POST /ordertemps
def create
#ordertemp = Ordertemp.new(ordertemp_params)
if #ordertemp.save
render json: #ordertemp
else
render error: { error: 'Unable to create an order'}, status: 400
end
end
However, I'm getting an error in the next code:
private
def ordertemp_params
params.require(:ordertemp).permit(:name, :amount, :price)
end
I found the method permit is just related to hashes, so apparently my data is not in that format, so I tried to use different functions such as: .each_with_index.to_a, to_h, Hash but nothing seems to work.
So my questions are:
what function should I use to convert my data to a hash?
Do I need to iterate my data in order to save each item into the table?
Thanks a lot
You need to add more to your question. Go to your web console and copy the actual params being submitted. Also what exactly are your errors?
You can look at this: https://codersloth.medium.com/rails-creating-multiple-records-from-a-single-request-a45261085164 as it covers much of what you are talking about. I'm guessing here because of your lack of info in your question but this might work:
def create
begin
OrderTemp.transaction do
#ordertemp = Ordertemp.create!(ordertemp_params)
end
rescue ActiveRecord::RecordInvalid => exception
# omitting the exception type rescues all StandardErrors
#ordertemps = {
error: {
status: 422,
message: exception
}
}
end
render json: #ordertemp
end
And in your params method:
private
def ordertemp_params
params.permit(:name, :amount, :price)
end
Related
So there doesn't appear to be any clean way to generically allow Hash field with strong parameters. This may of course be a strong parameters issue but I'm curious if there is a workaround. I have a model with some fields...
field :name, type: String
field :email, type: String
field :other_stuff, type: Hash, default: {}
Now I could just permit everything:
params.require(:registration).permit!
But that isn't really a great idea and what I'd like to do is something like...
params.require(:registration).permit(:name, :email, { other_stuff: {} })
However this doesn't seem to be possible with strong parameters, it isn't possible to just whitelist a hash as a property (yay for SQL centric ActiveRecord APIs!). Any ideas how this might be done, or is my best bet to submit a Rails patch to allow for this scenario.
Ok, after researching this, I found an elegant solution that I will start using too:
params.require(:registration).permit(:name).tap do |whitelisted|
whitelisted[:other_stuff] = params[:registration][:other_stuff]
end
source: https://github.com/rails/rails/issues/9454#issuecomment-14167664
If necessary nested attributes can also be permitted as follows:
def create_params
params[:book]["chapter"].permit(:content)
end
For a field that allows nested hashes, I use the following solution:
def permit_recursive_params(params)
params.map do |key, value|
if value.is_a?(Array)
{ key => [ permit_recursive_params(value.first) ] }
elsif value.is_a?(Hash) || value.is_a?(ActionController::Parameters)
{ key => permit_recursive_params(value) }
else
key
end
end
end
To apply it to for example the values param, you can use it like this:
def item_params
params.require(:item).permit(values: permit_recursive_params(params[:item][:values]))
end
I´m developing a grails app, and I already have a domain class "ExtendedUser" wich has info about users like: "name", "bio", "birthDate". Now I´m planning to do statistics about user´s age so I have created another controller "StatisticsController" and the idea is to store all the birthDates in a local array so I can manage multiple calculations with it
class StatisticsController {
// #Secured(["ROLE_COMPANY"])
def teststat(){
def user = ExtendedUser.findAll() //A list with all of the users
def emptyList = [] //AN empty list to store all the birthdates
def k = 0
while (k<=user.size()){
emptyList.add(user[k].birthDate) //Add a new birthdate to the emptyList (The Error)
k++
}
[age: user]
}
}
When I test, it shows me this error message: Cannot get property 'birthDate' on null object
So my question is how is the best way to store all the birthdates in an single array or list, so I can make calculations with it. Thank you
I prefer to .each() in groovy as much as possible. Read about groovy looping here.
For this try something like:
user.each() {
emptylist.push(it.birthdate) //'it' is the name of the default iterator created by the .each()
}
I don't have a grails environment set up on this computer so that is right off the top of my head without being tested but give it a shot.
I would use this approach:
def birthDates = ExtendedUser.findAll().collect { it.birthDate }
The collect method transforms each element of the collection and returns the transformed collection. In this case, users are being transformed into their birth dates.
Can you try:
List dates = ExtendedUser.findAll().birthDate
I am creating the bulkloader.yaml automatically from my existing schema and have trouble downloading my data due the repeated=True of my KeyProperty.
class User(ndb.Model):
firstname = ndb.StringProperty()
friends = ndb.KeyProperty(kind='User', repeated=True)
The automatic created bulkloader looks like this:
- kind: User
connector: csv
connector_options:
# TODO: Add connector options here--these are specific to each connector.
property_map:
- property: __key__
external_name: key
export_transform: transform.key_id_or_name_as_string
- property: firstname
external_name: firstname
# Type: String Stats: 2 properties of this type in this kind.
- property: friends
external_name: friends
# Type: Key Stats: 2 properties of this type in this kind.
import_transform: transform.create_foreign_key('User')
export_transform: transform.key_id_or_name_as_string
This is the error message I am getting:
google.appengine.ext.bulkload.bulkloader_errors.ErrorOnTransform: Error on transform. Property: friends External Name: friends. Code: transform.key_id_or_name_as_string Details: 'list' object has no attribute 'to_path'
What can I do please?
Possible Solution:
After Tony's tip I came up with this:
- property: friends
external_name: friends
# Type: Key Stats: 2 properties of this type in this kind.
import_transform: myfriends.stringToValue(';')
export_transform: myfriends.valueToString(';')
myfriends.py
def valueToString(delimiter):
def key_list_to_string(value):
keyStringList = []
if value == '' or value is None or value == []:
return None
for val in value:
keyStringList.append(transform.key_id_or_name_as_string(val))
return delimiter.join(keyStringList)
return key_list_to_string
And this works! The encoding is in Unicode though: UTF-8. Make sure to open the file in LibreOffice as such or you would see garbled content.
The biggest challenge is import. This is what I came up with without any luck:
def stringToValue(delimiter):
def string_to_key_list(value):
keyvalueList = []
if value == '' or value is None or value == []:
return None
for val in value.split(';'):
keyvalueList.append(transform.create_foreign_key('User'))
return keyvalueList
return string_to_key_list
I get the error message:
BadValueError: Unsupported type for property friends: <type 'function'>
According to Datastore viewer, I need to create something like this:
[datastore_types.Key.from_path(u'User', u'kave#gmail.com', _app=u's~myapp1')]
Update 2:
Tony you are to be a real expert in Bulkloader. Thanks for your help. Your solution worked!
I have moved my other question to a new thread.
But one crucial problem that appears is that, when I create new users I can see my friends field shown as <missing> and it works fine.
Now when I use your solution to upload the data, I see for those users without any friend entries a <null> entry. Unfortunately this seems to break the model since friends can't be null.
Changing the model to reflect this, seems to be ignored.
friends = ndb.KeyProperty(kind='User', repeated=True, required=False)
How can I fix this please?
update:
digging further into it:
when the status <missing> is shown in the data viewer, in code it shows friends = []
However when I upload the data via csv I get a <null>, which translates to friends = [None]. I know this, because I exported the data into my local data storage and could follow it in code. Strangely enough if I empty the list del user.friends[:], it works as expected. There must be a beter way to set it while uploading via csv though...
Final Solution
This turns out to be a bug that hasn't been resolved since over one year.
In a nutshell, even though there is no value in csv, because a list is expected, gae makes a list with a None inside. This is game breaking, since retrieval of such a model ends up in an instant crash.
Adding a post_import_function, which deletes the lists with a None inside.
In my case:
def post_import(input_dict, instance, bulkload_state_copy):
if instance["friends"] is None:
del instance["friends"]
return instance
Finally everything works as expected.
When you are using repeated properties and exporting to a CSV, you should be doing some formatting to concatenate the list into a CSV understood format. Please check the example here on import/export of list of dates and hope it can help you.
EDIT : Adding suggestion for import transform from an earlier comment to this answer
For import, please try something like:
`from google.appengine.api import datastore
def stringToValue(delimiter):
def string_to_key_list(value):
keyvalueList = []
if value == '' or value is None or value == []: return None
for val in value.split(';'):
keyvalueList.append(datastore.Key.from_path('User', val))
return keyvalueList
return string_to_key_list`
if you have id instead of name , add like val = int(val)
I am using MultipleChoiceField and already mentioned required=False. Then Why I am getting this error Username: Enter a list of values.
def get_my_choices():
users = User.query()
choices_list = [(x.key.id(), x.email) for x in users]
return choices_list
class MyForm(forms.Form):
username = forms.MultipleChoiceField(required=False, choices=get_my_choices())
Am I doing something wrong? thanks :-)
You only want to return one choice, but you are using MultipleChoiceField.
If you change it to ChoiceField it will work.
Implement a Widgetclass that knows how to fetch its data from the MultiValueDict:
class SelectMultiple(forms.widgets.SelectMultiple):
def value_from_datadict(self, data, files, name):
try:
return data.getall(name)
except:
return data.get(name, None)
and pass this to the Fields constructor: MultipleChoiceField(widget=SelectMultiple)
Use item_type=unicode for the field.
field = db.ListProperty(item_type=unicode, choices=...)
Source :http://vanderwijk.info/blog/google-app-engine-django-and-multiplechoicefield/
I'm currently building a data generator. First I want to implement is PESEL (kind of personal ID in Poland based on birth date) generator - I want to enter in form a temporary data with start and end birth date interval - I don't want to store it in database (or I should I do it?)
Here is my pesel controller:
def new
#pesel = Array.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #pesel }
end
end
but I've got an "undefined method `model_name' for NilClass:Class" error - is it a good way anyway of solvint this case? I read somewhere that using temporary variables is not with 'The Ruby Way' - if my solution is wrong, please suggest the correct one. (e.g pass this vars through cookies? hash? helper method?)
here is the stacktrace(I think):
Started GET "/pesel" for 127.0.0.1 at 2011-12-05 16:18:20 +0100
Processing by PeselController#new as HTML
Rendered pesel/new.html.erb within layouts/application (1513.9ms)
Completed 500 Internal Server Error in 1793ms
ActionView::Template::Error (undefined method `model_name' for NilClass:Class):
1: <%= simple_form_for #pesel do |f| %>
2: <%= f.input :date_of_birth, :as => :date, :start_year => Date.today.year - 90,
3: :end_year => Date.today.year - 12, :discard_day => true,
4: :order => [:month, :year] %>
app/views/pesel/new.html.erb:1:in `_app_views_pesel_new_html_erb__708648673_90148530'
app/controllers/pesel_controller.rb:7:in `new'
Rendered /home/ofca/.rvm/gems/ruby-1.9.2-p290/gems/actionpack-3.1.1/lib/action_dispatch/middleware/templates/rescues/_trace.erb (5.6ms)
Rendered /home/ofca/.rvm/gems/ruby-1.9.2-p290/gems/actionpack-3.1.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (4.0ms)
Rendered /home/ofca/.rvm/gems/ruby-1.9.2-p290/gems/actionpack-3.1.1/lib/action_dispatch/middleware/templates/rescues/template_error.erb within rescues/layout (17.6ms)
form_for assumes certain properties exist for the object you pass it, such as model_name.
Instead of using form_for #pesel, just use form_tag and the related _tag methods.
Use a Pesel model. Models are not tables, and your model doesn't have to write anything to the database. Just don't inherit from ActiveRecord, but do provide a model_name and any other fields the form_for helper expects.