Accesing a value in different file with attr accessor - ruby-on-rails

I have a form that is used to generate a report. In this form I have a number of flags set - that will then dictate what my report does.
These variables are then passed to the model and I pick them up
attr_accessor :make_charge
At this point I know I have the variable as I can log it.
I then pass off to the generatereport file.
This file picks up
attr_accessor :member
attr_reader :make_charge
The report is generated - and the various properties the member has are ok, but I cannot access the value of make charge.
How how do I set a value in one file and then access in another? It would seem to me the attr_accessor and attr_reader do this - but I seem to be doing it wrong. (Which we have all agreed on)
The report is generated just fine - what I want to do is a new action on the records of this report - based on a setting in the original form submission. I was hoping to do it in one process - to set the parameters - have the report run and then the records adjusted. The flag is not part of the model. it's a flag if set do something once report is complete.
The report generator is
MemberAccountsByStatusAndDateReportGenerator.new(
Member.
includes(:balances).
joins(:balances).
where{with_balances}.
where(status: report_options[:status]).
where{last_login_at >= start_date }.
where{last_login_at <= end_date}
).to_csv_file(file_name, linesep: "\r\n", colsep: ",")
once the report is run I want to be able to do something to the records based on a different report_option [:variable] But I need to get that variable to the action that creates the file.

Related

Unpermitted parameters issue Ruby on Rails 5

I'm currently trying to understand how permitted parameters works in ruby.
Usually, in my_model.rb I have:
has_many: some_other_model
*
*
*
def my_model_params
params.require(:my_model).permit( :column1, some_other_model_attributes %i[other_column1])
etc...
and in the update function
my_object.update_attributes(my_model_params)
with a well formatted json which has some my_model root, and some_other_model_attributes as a child (array) with values.
My problem is I receive a json like this one
However the different arrays inside (such as codification, general_information) do contain attributes of the mission (general_information contains reference that is a column in the mission table) but there isn't any column named codification, or relation to a codification_attributes.
So, when I add :
general_information: %i[reference] in the permitted params, it says unknown attribute 'general_information' for Mission.
If not, no error are raised but in the log I can see unpermitted_parameter: general_information. And my object is not updated.
Finally if I reject it, there is no more unpermitted_parameter: general_information in the log but my object is not updated either.
I tried to set config.action_controller.action_on_unpermitted_parameters to false in my development config, it did nothing and it's probably a bad idea for production environment anyway.
The use of .permit! (even if it works) is currently not an option. And even though I think the json needs to be re-formatted it'd be better to find an other solution.
Thanks for the help.
unpermitted_parameter: ... in logs in not a problem which you need to fix, it's just an info.
How it works - you just permit needed parameters, you may think about them as a hash. Unpermitted parameters will not go into the model even if they are present in params. It means when you call
my_object.update_attributes(my_model_params)
it works like
my_object.update_attributes(column1: value_for_column1_from_params)
Keys in params should be named exactly as columns in the model, otherwise you need to prepare params somehow before create/update

How can I build this recursive method in rails/ruby?

I'm using a form object pattern in rails, and am generating a data map that consists of nested form objects that I want to commit to the DB.
For example, I have something like this:
ProductFormObject
FeatureFormObject1
KeyFormObject (ex: Color)
ValueFormObject (ex: Red)
FeatureFormObject2
KeyFormObject (ex: Size)
ValueFormObject (ex: Large)
So what I would like to do is recursively validate this data, but I need to start from the bottom up.
In other words, a product without features is invalid, so before I can validate the product I need to validate the features. A feature without a key/value pair (ex: color = red) is invalid. So I need to first validated the key and value form objects.
I figure I can set the state of each form object as having been validated or not. But I'm really not sure how to get this to work from the bottom-up.
I don't really have any code that would be worth sharing, as I'm in the process of building this out now. Pseudo-code could help for now too, and I'll post the final results once I get it working.
I think you're overcomplicating things - this doesn't need to be recursive or bottom up.
On ProductFormObject you could have something like
def valid?
feature_form_objects.any? && feature_form_objects.all?(&:valid?)
end
To say that there must be at least one child object and they must all be valid.
And then the valid? method on FeatureFormObject just needs to verify that both its key and value are valid? (Possibly first checking that they are not nil - depend on how you construct things this may not be possible). You might also need to check that the combination of key and value are valid.
def valid?
key_form_object.valid? && value_form_object.valid?
end

create dynamic default values for column in rails?

I am not sure how to go about this, or if there is a better way to do this, but I have a table called leads(many) and it references agent (one).
I want to make a migration that sets a default value for the agent_id column in the leads table. But i want the default value to loop through all the agent ids. Im not sure how to do this!? Should i use a call back, or should i do in migration file?
Here is the actual question im trying to tackle:
When new leads are created assign it to an agent using a “round robin” That way new leads are distributed evenly across all the agents.
Ive attached a screenshot using SUDO code (i know its not functional as is) as to what I am thinking of doing. Any tips?
(Using ruby on rails w/ postgresql)
I think it makes sense to handle this functionality as part of the main app, and not within migration, as there seem to be a significant chunk of functionality to handle.
Probably best to handle it as part of an after_create callback in the Lead model, and use a class variable to track the next agent to be assigned as follows:
class Lead
# Assign the class variable to the first agent
##next_agent = Agent.first
after_create :set_agent
...
private
# Called by the after_create callback
# Sets the agent_id, and updates the ##next_agent class variable
def set_agent
self.agent_id = ##next_agent.id
##next_agent = find_next_agent
end
## Called from the set_agent method
## Finds the next agent based on the current value of ##next_agent
def find_next_agent
##next_agent = Agent.find(##next_agent.id + 1)
##next_agent = Agent.first unless #next_agent
end
end
The find_next_agent logic above is a simplistic example, assuming that all Agent objects have ids that increment by 1, and there are no gaps (i.e. no deletions in the table).

rails if statement in controller - checking nil

I have an if statement in my update action in one of my controllers. It looks like this:
if !#bid.attributes.values.include?(nil)
build(#bid.id)
end
I am checking to see if there are any nil valued attributes in my Bid object before building a bid report. I know the build method works fine because it builds a report when not wrapped in the if statement. When it is wrapped in this if statement, it doesn't run. I have checked to make sure that there are no nil values in the object. I went into the rails console and all attributes have non-nil values. In addition, I am able to check this in the views to confirm that there are no nil values.
I have also tried writing as:
build(#bid.id) unless #bid.attributes.values.include?(nil)
and a couple other variations. None are allowing the build to run.
Your code seems fine, I'm betting it's your data that's the problem instead. Mostly likely, assuming this an active record instance, the attribute is id which will be nil until the new record gets saved.
What do you get in the terminal when you add this line right before your if?
puts #bid.attributes.to_yaml
You should be able to see what has values and what does not. And I'm pretty sure at least one of those values is nil.
I would recommend being more explicit about exactly which fields are required. And this is exactly what validations are for.
class Person < ActiveRecord::Base
validates :name, presence: true
end
You explicitly validate each field so that when it's absent you get a very specific error message about why: "Person name can't be blank." So instead of wondering why it wont save, you get told why at the point it fails to save.

Rails Limit Model To 1 Record

I am trying to create a section in my app where a user can update certain site wide attributes. An example is a sales tax percent. Even though this amount is relatively constant, it does change every few years.
Currently I have created a Globals model with attributes I want to keep track of. For example, to access these attributes where needed, I could simply do something like the following snippet.
(1+ Globals.first.sales_tax) * #item.total
What is the best way to handle variables that do not change often, and are applied site wide? If I use this method is there a way to limit the model to one record? A final but more sobering question.......Am I even on the right track?
Ok, so I've dealt with this before, as a design pattern, it is not the ideal way to do things IMO, but it can sometimes be the only way, especially if you don't have direct disk write access, as you would if deployed on Heroku. Here is the solution.
class Global < ActiveRecord::Base
validate :only_one
private
def only_one
if Global.count >= 1
errors.add :base, 'There can only be one global setting/your message here'
end
end
end
If you DO have direct disk access, you can create a YAML config file that you can read/write/dump to when a user edits a config variable.
For example, you could have a yaml file in config/locales/globals.yml
When you wanted to edit it, you could write
filepath = "#{Rails.root}/config/locales/globals.yml"
globals = YAML.load(File.read("#{Rails.root}/config/locales/globals.yml"))
globals.merge!({ sales_tax: 0.07 })
File.write(filepath) do |f|
f.write YAML.dump(globals)
end
More on the ruby yaml documentation
You could also use JSON, XML, or whatever markup language you want
It seems to me like you are pretty close, but depending on the data structure you end up with, I would change it to
(1+ Globals.last.sales_tax) * #item.total
and then build some type of interface that either:
Allows a user to create a new Globals object (perhaps duplicating the existing one) - the use case here being that there is some archive of when these things changed, although you could argue that this should really be a warehousing function (I'm not sure of the scope of your project).
Allows a user to update the existing Globals object using something like paper_trail to track the changes (in which case you might want validations like those presented by #Brian Wheeler).
Alternatively, you could pivot the Global object and instead use something like a kind or type column to delineate different values so that you would have:
(1+ Globals.where(kind: 'Colorado Sales Tax').last) * #item.total
and still build interfaces similar to the ones described above.
You can create a create a class and dump all your constants in it.
For instance:
class Global
#sales_tax = 0.9
def sales_tax
#sales_tax
end
end
and access it like:
Global.sales_tax
Or, you can define global variables something on the lines of this post

Resources