Rails does not write column - ruby-on-rails

i have a totally strange problem:
Rails 6.0.0
ruby 2.5.7
mysql 8.0.15
it saves the most columns, but not all.
p.errors.full_messages delivers emtpy array and p.valid? delivers true.
but, p.to_geocode does not be set to true in the database, p.location_string is also not saved.
But, all the values, which are advised by the loop (hash.keys.each {..) are correctly stored.
what may there be?
thanks in advance!
Chris
Code:
def write_project(hash)
# MAKE RECORD
p = Project.new
hash.keys.each {|k| p[k.to_sym] = hash[k.to_sym]}
p.created_by = session[:login_name]
p.group = 'antenna_project'
#default_values.each do |k, v|
unless p[k.to_sym].present?
p[k.to_sym] = v
end
end
p.import_id = #import.id
# ERROR HANDLING SAVE
p[:to_geocode] = true
p.location_string = [hash[:street].to_s, hash[:zip].to_s, hash[:city].to_s, 'switzerland'].reject(&:empty?).join(', ')
unless p.save(validate: false)
e = "COULD NOT SAVE RECORD"
log_import_error(nil, e)
return e
end
#import.block_others_until = (DateTime.now + 1.seconds)
#import.save
return "SUCCESS"
end

Related

Is there a method to set a value in rails to nil and save?

What I'm thinking of is something where I can say:
e = Foo.new
e.bar = "hello"
e.save
e.reload
e.bar.nil!
e.reload
e.bar.nil? => true
Kind of #touch but sets nil and saves.
EDIT
Super sorry guys. I mean this:
e = Foo.new
e.bar = "hello"
e.save
e.reload
e.bar.nil!
e.reload
e.bar.nil? => true
Maybe something like:
module ActiveRecord
class Base
def nil!(*names)
unless persisted?
raise ActiveRecordError, <<-MSG.squish
cannot nil on a new or destroyed record object. Consider using
persisted?, new_record?, or destroyed? before nilling
MSG
end
unless names.empty?
changes = {}
names.each do |column|
column = column.to_s
changes[column] = write_attribute(column, nil)
end
primary_key = self.class.primary_key
scope = self.class.unscoped.where(primary_key => _read_attribute(primary_key))
if locking_enabled?
locking_column = self.class.locking_column
scope = scope.where(locking_column => _read_attribute(locking_column))
changes[locking_column] = increment_lock
end
clear_attribute_changes(changes.keys)
result = scope.update_all(changes) == 1
if !result && locking_enabled?
raise ActiveRecord::StaleObjectError.new(self, "nil")
end
#_trigger_update_callback = result
result
else
true
end
end
end
end
Put that in an initializer and it'll let you null out the title of a comment with Comment.last.nil!(:title).
You can't save a nil to the database, and furthermore, once an object has been created as a particular class you can never change that. It can only be converted by creating a new object, something an in-place modifier like this hypothetical nil! does.
The closest thing you can get is:
e = Foo.new
e.bar = "hello"
e.save
e.reload
e.delete!
e.reload
e.destroyed? # => true
f = Foo.find_by(id: e.id)
f.nil? # => true

OpenStruct issue with Ruby 2.3.1

In Ruby 2.1.5 and 2.2.4, creating a new Collector returns the correct result.
require 'ostruct'
module ResourceResponses
class Collector < OpenStruct
def initialize
super
#table = Hash.new {|h,k| h[k] = Response.new }
end
end
class Response
attr_reader :publish_formats, :publish_block, :blocks, :block_order
def initialize
#publish_formats = []
#blocks = {}
#block_order = []
end
end
end
> Collector.new
=> #<ResourceResponses::Collector>
Collector.new.responses
=> #<ResourceResponses::Response:0x007fb3f409ae98 #block_order=[], #blocks= {}, #publish_formats=[]>
When I upgrade to Ruby 2.3.1, it starts returning back nil instead.
> Collector.new
=> #<ResourceResponses::Collector>
> Collector.new.responses
=> nil
I've done a lot of reading around how OpenStruct is now 10x faster in 2.3 but I'm not seeing what change was made that would break the relationship between Collector and Response. Any help is very appreciated. Rails is at version 4.2.7.1.
Let's have a look at the implementation of method_missing in the current implementation:
def method_missing(mid, *args) # :nodoc:
len = args.length
if mname = mid[/.*(?==\z)/m]
if len != 1
raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
end
modifiable?[new_ostruct_member!(mname)] = args[0]
elsif len == 0
if #table.key?(mid)
new_ostruct_member!(mid) unless frozen?
#table[mid]
end
else
err = NoMethodError.new "undefined method `#{mid}' for #{self}", mid, args
err.set_backtrace caller(1)
raise err
end
end
The interesting part is the block in the middle that runs when the method name didn't end with an = and when there are no addition arguments:
if #table.key?(mid)
new_ostruct_member!(mid) unless frozen?
#table[mid]
end
As you can see the implementation first checks if the key exists, before actually reading the value.
This breaks your implementation with the hash that returns a new Response.new when a key/value is not set. Because just calling key? doesn't trigger the setting of the default value:
hash = Hash.new { |h,k| h[k] = :bar }
hash.has_key?(:foo)
#=> false
hash
#=> {}
hash[:foo]
#=> :bar
hash
#=> { :foo => :bar }
Ruby 2.2 didn't have this optimization. It just returned #table[mid] without checking #table.key? first.

Neo4j gem - Handling collection query with index

To avoid making the last question full of edits, I am spinning off a new question on debugging this. Original question was this Neo4j gem - Plucking multiple nodes/relationships
This is sorta where I ended up. There is some flaw with the day detection but as a query it does work for now. #collection returns a slew of things as written.
Event.rb
def self.reminder
one_day = 1.day.to_i
time = Time.zone.now.to_i
#collection = Event.as(:e).where( "( ( e.date_start - {current_time} ) / {one_day_p} ) < {one_p} " ).users(:u, :rel).where(setting_reminder: true).rel_where(reminded: false ).params(one_day_p: one_day, current_time: time, one_p: 1).pluck(:e, 'COLLECT(u)', 'COLLECT(rel)')
#collection.each do |event, users, rels|
users.each_with_index do |user, i|
UserMailer.reminder(event,user[i]).deliver
end
rels.each_with_index do |rels, i|
rels[i].reminded = true
end
end
end
I originally had it as the last answer did, but I think I need to track both the indexes of the user and the rel nested within the each block.
Running in rails c, when I run Event.reminder I get
TypeError: 0 is not a symbol
What's wrong with my nested loop?
#collection is one big array that contains other arrays. You can't do #collection.each do |event, users, rels|, you need to return each array within it and then loop through those. Two ways:
#collection = Event.as(:e).where( "( ( e.date_start - {current_time} ) / {one_day_p} ) < {one_p} " ).users(:u, :rel).where(setting_reminder: true).rel_where(reminded: false ).params(one_day_p: one_day, current_time: time, one_p: 1).pluck(:e, 'COLLECT(u)', 'COLLECT(rel)')
#collection.each do |row|
event = row[0]
users = row[1]
rels = row[2]
users.each_with_index do |user, i|
UserMailer.reminder(event, user).deliver
rels[i].reminded = true
rels[i].save
end
end
# OR
events = collection.map { |row| row[0] }
users = collection.map { |row| row[1] }
rels = collection.map { |row| row[2] }
events.each_with_index do |event, i|
UserMailer.reminder(event, users[i]).deliver
rels[i].reminded = true
rels[i].save
end
I think you just need to do a normal each:
users.each do |user|
UserMailer.reminder(event,user).deliver
end

Cant found model with out an ID in rails 3.2.12

i ve this method. I m not at all able to understand the error which is
Couldn't find Company without an ID
in ActiveRecord::RecordNotFound in CustomersController#bulk_create
This method is written to create customers for a company in bulk by taking their name and numbers in format name:number.
The method is as follows:
def bulk_create
res = ""
comp_id = params[:customer][:selected_companies].delete_if{|a| a.blank?}.first
comp = Company.find(comp_id)
s = SentSmsMessage.new
s.set_defaults
s.data = tmpl("command_signup_ok", customer, comp) unless params[:customer][:email].length > 0
s.data = params[:customer][:email] if params[:customer][:email].length > 0
s.company = comp if !comp.nil?
s.save
unless comp_id.blank?
params[:customer][:name].lines.each do |line|
(name, phone) = line.split(/\t/) unless line.include?(":")
(name, phone) = line.split(":") if line.include?(":")
phone = phone.gsub("\"", "")
phone = phone.strip if phone.strip.to_i > 0
name = name.gsub("\"", "")
name = name.gsub("+", "")
phone = "47#{phone}" if params[:customer][:active].to_i == 1
customer = Customer.first(:conditions => ["phone_number = ?", phone])
if customer.nil?
customer = Customer.new
customer.name = name
# customer.email
# customer.login
# customer.password
customer.accepted_agreement = DateTime.now
customer.phone_number = phone
customer.active = true
customer.accepted_agreement = DateTime.now
customer.max_msg_week = params[:customer][:max_msg_week]
customer.max_msg_day = params[:customer][:max_msg_day]
customer.selected_companies = params[:customer][:selected_companies].delete_if{|a| a.blank?}
res += "#{name} - #{phone}: Create OK<br />" if customer.save
res += "#{name} - #{phone}: Create failed<br />" unless customer.save
else
params[:customer][:selected_companies].each do |cid|
new_company = Company.find(cid) unless cid.blank?
if !new_company.nil?
if !customer.companies.include?(new_company)
customer.companies << new_company
if customer.save
res += "#{name} - #{phone}: Customer exists and the customer was added to the firm #{new_company.name}<br />"
else
res += "#{name} - #{phone}: Customer exist, but something went wrong during storage. Check if the client is in the firm.<br />"
end
else
res += "#{name} - #{phone}: Customer exists and is already on firm #{new_company.name}<br />"
end
end
end
end
s.sms_recipients.create(:phone_number => customer.phone_number)
end
s.save
s.send_as_sms
#result = res
respond_to do |format|
format.html { render "bulk_create"}
end
else
#result = "You have not selected any firm to add these users. Press the back button and try again."
respond_to do |format|
format.html { render "bulk_create"}
end
end
end
I want to update one situation here. That when i submit the form blank then it gives this error. Also if i filled the form with the values then its show the situation which the method is returning in case of fail.
res += "#{name} - #{phone}: Create failed <br />"
The tmpl method
private
def tmpl(setting_name, customer, company = nil)
text = ""
if customer.companies.count > 0
sn = "#{setting_name}_#{#customer.companies.first.company_category.suffix}".downcase rescue setting_name
text = Setting.value_by(sn) rescue ""
end
textlenth = text.length rescue 0
if textlenth < 3
text = Setting.value_by(setting_name) rescue Setting.value_by("command_error")
end
return fill_template(text, customer, company)
end
From the model customer.rb
def selected_companies=(cmps)
cmps.delete("")
# Check the old ones. Make a note if they are not in the list. If the existing ones are not in the new list, just remove them
self.companies.each do |c|
self.offer_subscriptions.find(:first, ["customer_id = ?", c]).destroy unless cmps.include? c.id.to_s
cmps.delete c.id.to_s if cmps.include? c.id.to_s
end
# Then create the new ones
cmps.each do |c2|
cmp = Company.find(:first, ["id = ?", c2])
if cmp && !c2.blank?
offerSubs = offer_subscriptions.new
offerSubs.company_id = c2
offerSubs.save
end
end
end
def selected_companies
return self.companies.collect{|c| c.id}
end
The association of customer is as follows:
has_many :offer_subscriptions
has_many :companies, :through => :offer_subscriptions
This code is written by the some one else. I m trying to understand this method but so far not being able to understand this code.
Please help.
Thanks in advance.
You are getting 'Couldn't find Company without an ID' error because your Company table doesn't contain record with id = comp_id
Change comp = Company.find(comp_id) to comp = Company.find_by_id(comp_id).
This will return nil instead of an error.
Add comp is not nil condition is already handled in your code.
Your comp_id line is returning nil.
comp_id = params[:customer][:selected_companies].delete_if{|a| a.blank?}.first
Post the params that get passed to this function and we could hopefully find out why. In the meantime you could enclose the block in a begin - rescue block to catch these errors:
begin
<all your code>
rescue ActiveRecord::RecordNotFound
return 'Unable to find a matching record'
end
try this:
comp = ""
comp = Company.find(comp_id) unless comp_id.nil?
instead of comp = Company.find(comp_id)
further nil checking present in your code.
Reason being
params[:customer][:selected_companies].delete_if{|a| a.blank?} = []
so [].first = nil
therefor, params[:customer][:selected_companies].delete_if{|a| a.blank?}.first = nil
and comp_id is nil
So check the log file and check what is coming in the parameter "selected_companies"
when you will find the parameter, everything will be understood well....

Rails :: Why the attribute change doesn't persist?

Controller:
#events = Event.all
#events.each { |e| e.user_subscribed = "someuser" }
#events.each { |e| puts "error" + e.user_subscribed }
I have attr_accessor :user_subscribed. but the error is can't convert nil into String as e.user_subscribed evaluates to nil.
I'm using mongoid on the backend.
edit: this works, but it just copies the whole array.
#events = #events.map do |e|
e.user_subscribed = "faaa"
e
end
If you're not saving the #events to the database, user_subscribed won't persist, unless you keep it in memory:
#events_with_subscription = #events.map { |e| e.user_subscribed = "someuser"; return e }
edited based on OP comments.
sounds like it might be better to just output Event.user_subscribed(current_user) directly in the view...but if you wanted to load up all that data before hand you could do:
#array_of_subscription_results = #Events.map{|e| e.user_subscribed(current_user,some,other,var,required) }
As long as user_subscribed returns the values you are interested in, thats what map will load into #array_of_subscription_results

Resources