CustomFieldFormat Redmine - redmine

I created my own CustomFieldFormat :
init.rb
Redmine::CustomFieldFormat.map do |fields|
fields.register
MyCustomFieldFormat.new('my', :label => :label_test, :order => 1 + 0.6)
end
lib/my_custom_field_format.rb
class MyCustomFieldFormat < Redmine::CustomFieldFormat
def format_value(value, field_format)
"test"
end
def show_value(custom_value)
"test"
end
end
I would like to modify the value of the field while updating. (For example, return "test" and not the value stored in the database). But nothing happens, there is always the true value in the field and not "test". Why ?
Thanks

Related

It is possible to somehow use forward_missing_to to fetch/set hash values?

I am building client for Asterisk Manager (AMI), which sending back "events" (strings in key-value format). Depending on event type the keys are different. Some known would be defined similar as a property, but I also want to access everything else similar way (I need only getter).
Below is example and I am confused about forward_missing_to, to fetch hash value (i.e. e.foo => e.data["foo"] and e.foo? => e.data["foo"]?
class Event
#data = Hash(String,String).new
def initialize(data : Hash(String, String))
#data.merge! data
end
# known field (event), here I could apply various validations etc.
def event=(#name : String)
#data["name"] = #name
end
def event : String
#data["name"].not_nil!
end
# Confusing about this:
forward_missing_to #data
end
Example of usage:
e = Event.new({"event" => "Test", "foo" => "bar"})
p e.event # => "Test" (only this works)
p e.foo # => expecting to get "bar"
p e.unknown # => should throw Unhandled exception: Missing hash key: "unknown" (KeyError)
p e.unknown? # => nil
forward_missing_to just means this:
e = Event.new({"event" => "Test", "foo" => "bar"})
# Same as invoking `foo` on the #data instance variable
# because you said forward_missing_to #data
e.foo
It doesn't mean invoking ["foo"] on #data.
You can do it like this:
macro method_missing(call)
{% if call.args.empty? && !call.named_args %}
#data[{{call.name.stringify}}]
{% else %}
{% raise "undefined method '#{call.name}' for #{#type}" %}
{% end %}
end
However, I wouldn't advise using method_missing, mainly because it might be eventually removed from the language (together with forward_missing_to).

RSpec: undefined method for #<ActionController::TestResponse. Testing a dynamic flash message

I have a simple spec testing the creation of an object of the Baseline class.
it "allows a user to create a baseline score with valid content" do
expect(#user.baselines.count).to eq(0)
#baseline = post(:create, :user_id => #user.id, :baseline => valid_attributes)
expect(response).to redirect_to '/patients/list'
expect(flash[:notice]).to eq("Baseline scores for case #{#baseline.case_id} was successfully created.")
expect(Baseline.all.count).to eq(1)
end
But I get this. I am uncertain where to begin with this - I am uncertain why I can't access the case_id attribute of #baseline.
NoMethodError:undefined method `case_id' for <ActionController::TestResponse:0x007f8f5ab4f3c0>
Just to show...these are the valid attributes
let(:valid_attributes) do {
:dx1 => "IPF",
:dxcon1 => 100,
:db1 => "Progressive",
:dbcon1 => 100,
:mgt=> "Drugs",
:biopsy => "Yes",
:patient_id => #patient.id,
:case_id => #patient.case,
}
end
post doesn't return a model instance it returns a TestResponse object which gives you access to headers, status code, etc. To access the object created as a side effect of calling the :create action you can do Baseline.last (in this case Baseline.first would also work since there are no existing baseline objects)
Also note - if you have an instance variable named #baseline that is assigned in the controller you can access that with assigns(:baseline)
expect(assigns[:baseline]).to be_a(Baseline)

Deeply associated column_names in counter_culture sum

When defining column_names in a counter_culture method, is it possible to deeply associate? In the docs and examples its always an attribute belonging to the model that is used to determine column_names. But, what if the attribute belongs to an associated model?
example, this works
# Account model
counter_culture :user,
column_name: Proc.new { |account| account.has_billable_hours? ? 'billed_hours_sum' : nil },
delta_column: 'billed_hours',
column_names: { ["account.billed_hours > ?", 0] => "billed_hours_sum" }
associated example
# Account model
counter_culture :user,
column_name: Proc.new { |account| account.clients.has_billable_hours? ? 'billed_hours_sum' : nil },
delta_column: 'billed_hours',
column_names: { ["accounts.clients.billed_hours > ?", 0] => "billed_hours_sum" }
If, for the above, you could (you can't) use joins in the column_names method it would look like this
joins(:account=>:client).where("accounts.clients.billed_hours > ?", 0)
The second example illustrates my question. How do you define the column_names when the attribute you need to evaluate does not belong to the parent model, but an associated model?
column_names is only need when calling counter_culture_fix_counts. So, I just 86'ed the column_names option from the the method call and created a rake task to update that counter/column manually.

Roo with rails4 giving undefined method `[]' for nil:NilClass

I'm trying to import CSV and Excel files into a rails 4 project (with validation) using the Roo gem, based on http://railscasts.com/episodes/396-importing-csv-and-excel.
I've made some changes to account for Rails4 instead of Rails3 and for changes to Roo, and my ProjectImporter model now looks like:
class ProductImport
include ActiveModel::Model
attr_accessor :file
def initialize(attributes = {})
attributes.each { |name, value| send("#{name}=", value) }
end
def persisted?
false
end
def save
if imported_products.map(&:valid?).all?
imported_products.each(&:save!)
true
else
imported_products.each_with_index do |product, index|
product.errors.full_messages.each do |message|
errors.add :base, "Row #{index + 2}: #{message}"
end
end
false
end
end
def imported_products
#imported_products ||= load_imported_products
end
def load_imported_products
spreadsheet = open_spreadsheet
spreadsheet.default_sheet = spreadsheet.sheets.first
puts "!!! Spreadsheet: #{spreadsheet}"
header = spreadsheet.row(1)
(2..spreadsheet.last_row).map do |i|
row = Hash[[header, spreadsheet.row(i)].transpose]
product = Product.find_by(id: row['id']) || Product.new
product.attributes = row.to_hash.slice(*['name', 'released_on', 'price'])
product
end
end
def open_spreadsheet
case File.extname(file.original_filename)
when ".csv" then
Roo::CSV.new(file.path, nil)
when '.tsv' then
Roo::CSV.new(file.path, csv_options: { col_sep: "\t" })
when '.xls' then
Roo::Excel.new(file.path, nil, :ignore)
when '.xlsx' then
Roo::Excelx.new(file.path, nil, :ignore)
when '.ods' then
Roo::OpenOffice.new(file.path, nil, :ignore)
else
raise "Unknown file type #{file.original_filename}"
end
end
end
When I try to run an import (using test CSV data), it fails on header = spreadsheet.row(1) with the error undefined method '[]' for nil:NilClass. The extra puts statement I've included confirms that spreadsheet itself isn't nil: it gives !!! Spreadsheet: #<Roo::CSV:0x44c2c98>. But if I try to call almost any of the expected methods on it, such as #last_row, it gives me the same undefined method error.
So what am I doing wrong?
I had the same problem, it seems a problem about file enconding, I used this code and it was fixed.
def open_spreadsheet
case File.extname(file.original_filename)
when ".csv" then Roo::CSV.new(file.path, csv_options: {encoding: "iso-8859-1:utf-8"})
when ".xls" then Roo::Excel.new(file.path, nil, :ignore)
when ".xlsx" then Roo::Excelx.new(file.path, nil, :ignore)
else raise "Unknown file type: #{file.original_filename}"
end
end
I hope that helps for you.

Count an Attribute on a nested form?

Rails 3.2.12 and Ruby 1.9.3 and Haml
I would like to use the count of attribute to control the display of a 'link_to "remove"', but I am having problems with setting up the logic.
Following is some code from my form as it is currently:
.field
= codeline.label :name, "Units Alloc"
%br/
= codeline.text_field :units_alloc, :precision => 6, :scale => 2, :size => 10,
:class => "ui-state-default"
= codeline.hidden_field :_destroy
= link_to "remove", '#', class: "remove_fields"
this works well but I have the 'remove' link showing up and I would prefer it to only show if there are two :units_alloc attributes.
This is what I tried:
.field
= codeline.label :name, "Units Alloc"
%br/
= codeline.text_field :units_alloc, :precision => 6, :scale => 2, :size => 10,
:class => "ui-state-default"
- if :units_alloc.count > 1
= codeline.hidden_field :_destroy
= link_to "remove", '#', class: "remove_fields"
and here is my error:
NoMethodError in Contracts#new
Showing /home/tom/rails_projects/tracking/app/views/contracts
/_codeline_fields.html.haml where line #9 raised:
undefined method `count' for :units_alloc:Symbol
if I use units_alloc in the argument instead of the symbol, I still get an error:
NameError in Contracts#new
Showing /home/tom/rails_projects/tracking/app/views/contracts
/_codeline_fields.html.haml where line #9 raised:
undefined local variable or method `units_alloc' for
#<#<Class:0xadbde90>:0xa8956e8>
I tried to use 'codeline.units_alloc' but this did not work and the same error was flagged.
Any suggestions, or pointers to help me resolve this issue?
Thanks.
Solution: Thanks to James Scott Jr.
app/controller/contracts_controller.rb
def New
#show_remove = false
....
....
end
app/views/contracts/_codelines_fields.html.haml
.field
= codeline.label :name, "Units Alloc"
%br/
= codeline.text_field :units_alloc, :precision => 6, :scale => 2, :size => 10,
:class => "ui-state-default"
- if #show_remove
= codeline.hidden_field :_destroy
= link_to "remove", '#', class: "remove_fields"
- else
- #show_remove = true
And that did it ... the remove button only shows in the second and subsequent row of attributes.
By the time you're in the form (partial), codeline doesn't refer to an instance the instance of Codeline that the form (partial) is for, but an instance of an ActionView::Helpers::FormBuilder that simple knows how to associate information the the instance of Codeline. You knew that because in the first line of the partial, you have codeline.object.build_code.
So, if you want to access the information about the units_alloc associated, you would access them with codeline.object.units_alloc. That will give you your data for your conditional.
I would just like to add that if the purpose of your anchor tag is to remove elements from a form list using some javacscript, you might be using the wrong control for it. Anchor tags are not form elements, they should point to resources/content and are not there to be used as animation/client side behaviour triggers. According to the use case you describe, an input tag type=button would be a much more appropriated element for what you seem to be trying to achieve.