I created a taglib to shorten input field code. It presets 'name', 'value' and others. Now I need to get a bean value, but the field holding that value is dynamic.
See some code (shortened to better work out my problem):
gsp:
<g:validatedInputField bean="${command}" field="surname" />
<g:validatedInputField bean="${command}" field="name" />
taglib
def validatedInputField = { attrs, body ->
def field = attrs.field
def bean = attrs.bean
if (field && bean) {
def val = bean.field
out << "<input type=\"text\" name=\"$field\" bean=\"$bean\" value=\"$val\">"
}
}
So the problem is the following line. It does obviously not work because there is no field 'field' in the bean. I want it to be dynamically replaced by 'name' or 'surname' or whatever the value of the param 'field' is.
def val = bean.field
I tried exprimenting with various GString/interpolation variations, but nothing worked.
Of course I could just add another param to pass the value, but I feel like it shouldn't be required as I already have everything I need to get it in the taglib...
Can you please give me some directions?
Thanks
In groovy, you can refer to a member of an object dynamically by using GStrings. For example:
def val = bean."${field}"
You could even perform some logic inside the GString. Let's say you have a default field and you want to use the name inside the 'field' variable only if it is not null:
def val = bean."${field ? field : "default"}
If bean is an object instance and field is a String that represent a member of that object, you can try something like:
def val = bean."$field"
Related
I recently started with rails.
I have one task here, but I don't know what is best practice and how to do it.
I have form with checkbox currency? and input currency_code.
Only value currency_code will be stored in database.
What I need:
1. If checkbox currency? is TRUE => currency_code must be filled
2. If checkbox currency? is FALSE => currency_code will be reset to nil
How to validate 1. if currency? is not in database (table column) so model does not know about this?
In case 2. Where I should check this and reset value currency_code to nil?
For case 2. I have this in my controller, but I don't like. I think that there must be a better solution.
def data_params
parameters = params.require(:data).permit(
:currency_code
)
parameters[:currency_code] = nil unless params[:data][:currency].to_bool
parameters
end
The attribute 'currency?' which is not part of the model is called virtual attributes. In Rails, we can use virtual attributes by setting
attr_accessor :currency?
in your corresponding_model.rb.
Now you can use this 'currency?' attribute in your form like other model attributes.
For case 2, the plcaement for this kind of data validations is to validate them in the view before even coming into the model. you must use jquery / javascript or any script of your choice. Here I provide jQuery snippet.
If you are new for using jquery in rails app, follow this https://github.com/rails/jquery-rails
In your form_page.html.erb add ids to the html elements.
<%= f.check_box :currency?, id: 'currency_checkbox' %>
and
<%= f.text_field :currency_code, id: 'currency_code' %>
The jquery snippet
curreny_checkbox = $('#curreny_checkbox')
currency_code = $('#currency_code')
$(currency_checkbox).on('change', function(){
if(this.checked)
currency_code.val('2')
else
currency_code.val('')
})
In your controller, you can simply assign the values
def create
// other codes //
#obj.currency_code = params[:currency_code]
end
If you want to validate input on model level you should store the currency? in the database.
Still let say for some unexplained reasons you don't want to store currency? in you database(which I won't suggest you in any case). You can define a method in model.
def set_currency_if_required is_currency_required
self.currency_code = nil unless is_currency_required
end
in controller
def create
model = Model.new(data_params)
model.set_currency_if_required(params[:data][:currency].to_bool)
model.save
end
...
def data_params
parameters = params.require(:data).permit(
:currency_code
)
end
this way you will have better readability and a clear idea about whats going on with the code.
I have a taglib method and I fetch an object from database with string expressions to evaluate. From the docs, it should be possible to do sth like this:
out << "<div id=\"${attrs.book.id}\">"
But when I try to do the same for the object fetched from database, the expression between ${} does not get evaluated. I realized that the reason is because I have a String, so I tried to convert it to GString, but without any success.
// objectFromDb.content = "<div id=\"${attrs.book.id}\">"
def objectFromDb = fetchObjectFromDb()
def gStringExpression = "${objectFromDb.getContent()}"
out << gStringExpression
How can I achieve the evaluation of the expression inside the taglib? I want to have different variables for each object, so to use TemplateEngine is not possible as I don't know which variables will be used.
try this
def output = ""
def objectFromDb = fetchObjectFromDb()
def output += objectFromDb.getContent() // use toString() if needed
out << output
I have a form in rails with input values, and 1 of the values is a LOV (List of Values) and a second input field is also a LOV but depends on the input of the other field.
The input value of the first field is not saved in between. So I need to use that field value before it is saved.
So, the example:
I choose a company from the list of values of all companies for the field supplier, the second field supplier_address will be a LOV with all the addresses of that company, so the LOV of the second field is dependent on the value chosen in the first field, company.
What I tried:
def new
#purchase_requisition = PurchaseRequisition.new
#purchase_requisition.number = find_next_user_value("Purchase_Requisition")
##purchase_requisition.supplier_address_id = PurchaseRequisition.new.purchase_requisition_params[:supplier_id]
#purchase_requisition = PurchaseRequisition.new(purchase_requisition_params)
respond_to do |format|
#purchase_requisition.supplier_address_id = PurchaseRequisition.new.purchase_requisition_params[:supplier_id]
end
end
but I still get the error:
param is missing or the value is empty: purchase_requisition
Can someone please help me?
Thank you!!!
The error you're encountering isn't being caused by the code you've provided. You're probably using strong parameters and have a method like this:
def purchase_requisition_params
params.require(:purchase_requisition).permit(# some list of attributes #)
end
The problem is that params[:purchase_requisition] doesn't exist. Probably because the form_for in your view isn't referencing a purchase_requisition object. Try adding as: to your form_for to send your params under that param key:
form_for #requisition, as: :purchase_requisition, ....
Otherwise, you'll have to post more details about your view and controller to help isolate the issue you're having.
Also, in your controller code you want:
PurchaseRequisition.new(purchase_requisition_params[:supplier_id])
Instead of:
PurchaseRequisition.new.purchase_requisition_params[:supplier_id]
Supposing, all of your parameters belong to the same object (there isn't any nested attribute), this can be what you are looking for:
def purchase_requisition_params
params.require(:purchase_requisition).permit(:org_id, :document_type, :number, :supplier_id, :supplier_address_id, :partner_id, :project_id, :construction_site_id, :purchase_order_date, :expected_receiving_date, :promised_receiving_date, :supplier_order_number, :supplier_shipping_number, :supplier_invoice_number, :currency, :status) ##you don't need id here
end
I m in a situation where i need to convert an Object to string so that i can check for Invalid characters/HTML in any filed of that object.
Here is my function for spam check
def seems_spam?(str)
flag = str.match(/<.*>/m) || str.match(/http/) || str.match(/href=/)
Rails.logger.info "** was spam #{flag}"
flag
end
This method use a string and look for wrong data but i don't know how to convert an object to string and pass to this method. I tried this
#request = Request
spam = seems_spam?(#request.to_s)
Please guide
Thanks
You could try #request.inspect
That will show fields that are publicly accessible
Edit: So are you trying to validate each field on the object?
If so, you could get a hash of field and value pairs and pass each one to your method.
#request.instance_values.each do |field, val|
if seems_spam? val
# handle spam
end
If you're asking about implementing a to_s method, Eugene has answered it.
You need to create "to_s" method inside your Object class, where you will cycle through all fields of the object and collecting them into one string.
It will look something like this:
def to_s
attributes.each_with_object("") do |attribute, result|
result << "#{attribute[1].to_s} "
end
end
attribute variable is an array with name of the field and value of the field - [id, 1]
Calling #object.to_s will result with a string like "100 555-2342 machete " which you can check for spam.
I have a piece of code in Grails:
def product = Product.get(5) ?: new Product()
product.isDiscounted = product.isDiscounted ?: true
Problem is, if the isDiscounted property is already set for an existing product and it's false, I'll end up changing it to true. Is it possible to check if an object is transient?
In this case make the property Boolean instead of boolean, then the initial value will be null and not default to false. This will help validation too, since you can verify that a choice of false was intentional, and not just allowing the default value.
In general though you can use the isAttached() method (or the property style variant attached), e.g.
def product = Product.get(5) ?: new Product()
product.isDiscounted = product.attached ? product.isDiscounted ? true
This case can actually be even more compactly done with a default value in the constructor:
def product = Product.get(5) ?: new Product(discounted: true)