Cannot iterate through the attributes of an object - ruby-on-rails

I want to access the value of the document_id value in the DocumentUser instance variable and add it to an array. However, while the function ids is defined and I can access the id value with it, there is no function document_ids defined for this class. I could go ahead and define it, but my question is - can I access the document_ids value without doing that, perhaps by somehow using the map function (which confuses me)? I thought I could iterate through the model since it looks like it returns an Array, but no dice. Thanks!
[110] pry(#<#<Class:0x00007f99646b1b60>>)> #current_user.document_users.each { |n| puts n }
#<DocumentUser:0x00007f9957cce118>
=> [#<DocumentUser:0x00007f9957cce118
id: 382,
user_id: 26638,
document_id: 282,
created_at: Wed, 08 May 2019 15:05:42 CDT -05:00,
updated_at: Wed, 08 May 2019 15:05:42 CDT -05:00>]

Yes, it would be this:
#current_user.document_users.map(&:document_id)
which is a shorthand of this:
#current_user.document_users.map { |document_user| document_user.document_id }
Since it's probably ActiveRecord class, it's even better way to achieve this result, using pluck:
#current_user.document_users.pluck(:document_id)

Related

Puzzle: ActiveRecord object is persisted but cannot be retrieved with find

I am experiencing a head-scratcher in a non-Rails app using AR that I cannot figure out. I will simplify greatly, but here is the essence: I have a Download object that belongs to a Ledger. In one of my unit tests, I am experiencing this:
dl = create(:download, account: checking)
dl.ledger
=> <Byr::Ledger:0x00007fd176ce4740
id: 2,
name: "test_ledger_1",
org_name: "Test Ledger, Inc.",
street1: nil,
street2: nil,
city: nil,
state: nil,
zip: nil,
created_at: 2022-04-03 13:13:53.734003153 UTC,
updated_at: 2022-04-03 13:13:53.792451592 UTC,
default_account_id: 21,
short_name: "Test_ledger_1",
parent_percent: nil,
parent_id: nil,
accessed_at: 2022-04-03 13:13:53.791911547 UTC,
start_date: Mon, 01 Jan 2018,
cost_method: "fifo",
end_date: nil
> dl.ledger.peristed? => true
> Ledger.find(2) => nil with eval error: Couldn't find Byr::Ledger with 'id'=2
I use factory_bot to create the Download, dl, which in turn builds a ledger for it to go with, which purports to be persisted with id=2. But when I try to find the ledger with Ledger.find(2), it's not in the postgresql db.
Anybody have any idea what might be going on here?
I think you should use something like faker + factory_bot and mock resources to get access to params you need.
Here an example of use. Hope this helps
I finally got this to pass by explicitly passing the ledger into the Account factory on which the Download factory was created, like this:
let(:ldg) { create(:ledger, name: 'Willy') }
let(:checking) { create(:bank_account, ledger: ldg) }
let(:dl) { create(:download, account: checking) }
Suddenly, the disappearing ledgers abated. I believe the cuplrit may have been DatabaseCleaner wiping away the automatically-generated ledger from one example to the next. Using an explicit ledger just for the example in question kept it from being deleted underneath my feet.
Thanks, #Joe, for giving this some thought.

Prevent Grails 2.4.4 from accepting invalid dates

One of my co-workers has written an application in Grails 2.4.4 (I know, it's dated). One problem the app has is that you can enter a date like 2/31/2015 and it will be accepted as valid and will show up in your domain object as 3/3/2015 instead.
Is there any easy way to prevent this from happening using grails? Or do we instead have to rely on client side validation for this particular property?
Thanks.
Assuming that Grails is using DateFormat to parse the date String, the issue is that it's using a lenient Calendar. For example, with lenient set to true (the default), the result is as you described:
import java.text.SimpleDateFormat
def sdf = new SimpleDateFormat('MM/dd/y')
assert sdf.parse('02/31/2015').toString() == 'Tue Mar 03 00:00:00 EST 2015'
But, if you change it to false, you'll get an exception for the same date:
sdf.lenient = false
try {
sdf.parse('02/31/2015').toString() == 'Tue Mar 03 00:00:00 EST 2015'
} catch (java.text.ParseException ex) {
// java.text.ParseException: Unparseable date: "02/31/2015"
println 'Oops'
}
So to handle this validation in your controller, you can
Create a command object.
Have the command object accept the date as a String rather than a Date, and perform the date validation.
Modify the controller action to use the command object instead of params. This may require modifying the GSP code as well.

In this select tag helper, why the .push?

So a tutorial I was following had this nice method of building a drop-down select menu for selecting years.
The instructor very deliberately used .push in the 6th line of code below.
Why? What could it be pushing? I've never seen this way of using it.
# payment.rb
def self.year_options
(Date.today.year..(Date.today.year+10)).to_a
end
# new.html.erb
<%= p.select :card_expires_year,
options_for_select(Payment.year_options.push),
{include_blank:'Year'},
'data-stripe'=>'exp-year',
class:'form-control',
required:true
%>
Not sure why .push is being used here. The point of push is to add elements to an array.. Effectively that method is doing nothing here and you can call Payment.year_options without .push.
irb(main):003:0> options = (Date.today.year..(Date.today.year+10)).to_a
=> [2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025]
irb(main):004:0> options.push
=> [2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025]
It does nothing. Try it out in your rails console:
pry(main)> [1,2,3].push
=> [1, 2, 3]
Just delete it.
In case you're not aware, the purpose of push is to add an element to an array - so we could do this:
[1,2,3].push(4)
=> [1, 2, 3, 4]
and it'd add 4 to our array. Push with no parameter? No point.
I don't see any reason for doing that. Array#push is used to append an element to an array. In this case where no argument is given there is no impact to the initial array.
A possible use case (which does not apply here) is if Payment.year_options was an ActiveRecord::Relation where .push would evaluate it to an array (but it would still be a weird way to do it).

find_by_foo failing to return some records (but not others) in Rails 3

In my Rails app I have a model called Cycle with a "start" attribute that is a date. I'm running into a very strange problem where sometimes Cycle.find_by_start will return the expected record, but at other times it will return nil.
For example Cycle.find_by_start("2011-05-01") returns the following:
=> #<Cycle id: 45, created_at: "2011-05-15 22:38:35",
updated_at: "2011-05-15 22:38:35", user_id: 20,
start: "2011-05-01", ending: nil, startguess: false, endingguess: nil>
But running Cycle.find_by_start("2011-05-13") returns nil, even though there is a record with a matching start value. I've verified that the record exists and the start value matches by running the following at the Rails console.
irb(main):012:0> Cycle.find(47)
=> #<Cycle id: 47, created_at: "2011-05-23 01:28:59",
updated_at: "2011-06-21 00:38:34", user_id: 12,
start: "2011-05-13", ending: "2011-05-31", startguess: false, endingguess: false>
irb(main):011:0> Cycle.find(47).start == "2011-05-13".to_date
=> true
Possibly relevant info: Running Rails 3.0.7 in development mode with an SQLite database.
Any ideas or troubleshooting tips?
Edit 1
Log of the SQL queries used:
[94m19:10:11 active_record [37mCycle Load (1.0ms) SELECT "cycles".* FROM "cycles" WHERE "cycles"."start" = '2011-05-01' LIMIT 1
[94m19:10:19 active_record [37mCycle Load (0.0ms) SELECT "cycles".* FROM "cycles" WHERE "cycles"."start" = '2011-05-13' LIMIT 1
Dates.... you may have a parsing problem, with US/UK formats getting swapped around and confusing things. I often find it helps to make the date unambiguous (assuming English months):
Cycle.find_by_start("13 May 2011")
If :start is a date field, then it's best to pass find_by_start an actual Date object rather than a string. So:
Cycle.find_by_start(Date.parse("2011-05-13"))
(I'm using Date.parse to create the date object here, but you could also use Date.new or Date.today or some other method)
Passing a string to the finder method might work but, as you've discovered, might also not - depending on the database type and how the database interprets the string.

Trouble on counting ActiveRecord instances in an array

I am using Ruby on Rails 3 and I would like to solve a issue counting ActiveRecord instances in an array.
I have this code
data = Account.where({:name => "Test_name", :city => "Test_city"}).limit(10)
The data debug is
#<Account:0x000001029d2da0>#<Account:0x000001029d2c60>#<Account:0x000001029d2bc0>#<Account:0x000001029d2b20>
The data inspecting is
"[#<Account name: \"Test_name\", city: \"Test_city\">, #<Account … >, #<Account id… >, …]"
Doubt: The ##<...> should be something like #<Account...>,#<Account...>,<...> (note commas)?
If in my code I use the following
data_count = data.count
The data_count is
nil
Why is it nil? How should I count accounts?
If I use result = data.class the debug of result is nil, but if I use result = data.classthe debug is "{\"inheritable_attributes\":{}}".
If I use Account.find_by_name("Test_name") instead of Account.where(...) I get same results as above.
To get to the bottom of things, start the rails console with:
$ rails c
Given that Account is an ActiveRecord model, you should be able to do the following in the rails console:
> Account.all.count
=> 100
> Account.where(:status=>'active')
=> [ #<Account id: 1, name: "a1", ...>, #<Account id: 2, name: "a2", ...>, #<Account id: 3, name: "a3", ...>, ...]
I'm doing a lot of hand waving here with ... since I don't know your schema. Replace the where condition with whatever works for your situation. The returned value should look like an array with a list of all the rows in the database that match the condition. BTW, an array is a list of element, and inspect (as well as the default display in the console) show element separated by commas. I haven't used debug so I can't comment on what it should do.
You can verify that the returned value is an AREL, and should be able to do some other operations to verify things work as expected.
> Account.where(:status=>'active').class
=> ActiveRecord::Relation
> Account.where(:status=>'active').size
=> 99
> Account.where(:status=>'active').count
=> 99
> Account.where(:status=>'active').limit(10).count
=> 10
If these work as expected in the console, there may be something in the view that is obscuring the correct behavior. In that case you'll need to post the details of your view code. If the strange behavior still occurs in the console, I would suggest posting the minimal parts of the actual model code that still exhibit the problem, along with the migration so we can see the schema.
I think you are having some problem in where condition.
Can you show the attributes value used in where clause.
For me its working fine:
data = Account.where('id != 0').limit(10)
data_count = data.count
Use the following:
data = Account.where("id = 2 and email = 'test_email#test.com'")

Resources