Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
raej
Sep 25, 2003

"Being drunk is the worst feeling of all. Except for all those other feelings."
I have a list of beers that a user has in their cellar through cellared_beers so that a user has many beers through cellared_beers and vice versa. Each cellared_beer has extra data like year and size attached.

I am wanting to display the tallied results of the cellared_beers for a user on a page. Right now I have the following code which will get the counts:

code:
beer_groups = @user.cellared_beers.count(:group => [:beer_id,:year,:size])
which produces results like:
code:
=> {[1, 2008, "12oz"]=>1, [1, 2009, "12oz"]=>3, [1, 2010, "12oz"]=>1}
How do I map it out so that I can show the beer attributes based on beer_id, the year, size, and amount?

Something like:
Foo Beer(beer.name), Bar Brewery(beer.brewery.name),2008,12oz,1
Foo Beer(beer.name), Bar Brewery(beer.brewery.name),2009,12oz,3
Foo Beer(beer.name), Bar Brewery(beer.brewery.name),2010,12oz,1

EDIT:
Doing this in my controller:
code:
@beer_counts = beer_groups.each.map do |values,count|
"#{values[0]},#{values[1]},#{values[2]},#{count}"
end
spits out a nice array that I'm looking for:
code:
=> ["1,2008,12oz,1", "1,2009,12oz,3", "1,2010,12oz,1"]
For my view, how would I go about going through each in the @beer_counts array and use the first value to pull out a beer object?

Something like:
code:
@beer_counts.each do |values|
beer = Beer.find(values[0])
end
and be able to format the beer attributes(beer.name, beer.brewery.name, etc), as well as the cellared_beer attributes (year, size) in a view?

raej fucked around with this message at 21:39 on May 8, 2013

Adbot
ADBOT LOVES YOU

UxP
Aug 27, 2007

DreadCthulhu posted:

So by default the cookies are signed and basically given full trust regarding whether the user is who he claims he is? Permissions in there as well?

Yes. Signing them isn't a magic solution, but it prevents anyone from actually tampering with a cookie to change their user_id or role, or whatever you happen to store in a cookie, as long as no one knows what your session secret is ( 'config/initializers/secret_token.rb' ), as long as OpenSSL's HMAC remains trusted.

DreadCthulhu
Sep 17, 2008

What the fuck is up, Denny's?!

UxP posted:

Yes. Signing them isn't a magic solution, but it prevents anyone from actually tampering with a cookie to change their user_id or role, or whatever you happen to store in a cookie, as long as no one knows what your session secret is ( 'config/initializers/secret_token.rb' ), as long as OpenSSL's HMAC remains trusted.

Fair enough. I remember reading that the rationale is that if someone steals your secret token straight off your production box, you're probably screwed enough that the cookie is the last of your problems. As in, they likely have full access to the DB at that point, which is a lot more interesting.

If I'm understanding this correctly, the advantage of the signed cookie approach is that you don't have to have a server-side map of permissions/sessions, and you can effectively "distribute" the burden onto the clients? Keeping a properly synced user/permissions/sessions map in memory at all times and persisting it to db seems like extra work. I think some people use solutions like Redis for that as well.

raej
Sep 25, 2003

"Being drunk is the worst feeling of all. Except for all those other feelings."
Is there a way to break up a hash into an array? That should solve my previous problem.

controller
code:
beer_groups = @user.cellared_beers.count(:group => [:beer_id,:year,:size])
@beer_counts = beer_groups.each.map do |values,count|
      beer = Beer.find(values[0])
      "#{beer.id},#{beer.name},#{beer.brewery.id},#{beer.brewery.name},#{beer.style},#{beer.abv},#{values[1]},#{values[2]},#{count}"
    end
this spits out a single line for @beer_counts that looks like
code:
1,Test beer,1,Test Brewery 1,0,3.2,2008,12oz,1
So that if I do an .each do in my view, and pass in an array value, the return is a character of that string, not the value between the commas.

Is there a way to spit it out so that I can call beer[1] and get "Test beer" instead of ","?

Lexicon
Jul 29, 2003

I had a beer with Stephen Harper once and now I like him.

raej posted:

Is there a way to break up a hash into an array? That should solve my previous problem.

code:
>> { :abc => 1, :def => 2 }.to_a
=> [[:abc, 1], [:def, 2]]
:)

raej
Sep 25, 2003

"Being drunk is the worst feeling of all. Except for all those other feelings."

Lexicon posted:

code:
>> { :abc => 1, :def => 2 }.to_a
=> [[:abc, 1], [:def, 2]]
:)

Hmm, maybe what I have ins't a hash at all then? When I'm assembling the data in the controller, I need it to be broken up instead of one big string. Any ideas?

manero
Jan 30, 2006

raej posted:

Is there a way to break up a hash into an array? That should solve my previous problem.

controller
code:
beer_groups = @user.cellared_beers.count(:group => [:beer_id,:year,:size])
@beer_counts = beer_groups.each.map do |values,count|
 ...

The .each.map looks suspect. Just use map? I don't see why you'd want to chain .each.map like that.

Smol
Jun 1, 2011

Stat rosa pristina nomine, nomina nuda tenemus.
Are you trying to output CSV?

raej
Sep 25, 2003

"Being drunk is the worst feeling of all. Except for all those other feelings."

manero posted:

The .each.map looks suspect. Just use map? I don't see why you'd want to chain .each.map like that.

Changing it to just .map still spits out a big string

Smol posted:

Are you trying to output CSV?

I'm not trying to output csv. Ideally in my view I would call up each value to the view fir display purposes so that
code:
1,Test beer,1,Test Brewery 1,0,3.2,2008,12oz,1
translates to beer_id, beer_name, brewery_id, brewery_name, style, abv, year, size

Smol
Jun 1, 2011

Stat rosa pristina nomine, nomina nuda tenemus.
Ok, I think I understand your problem now. Does this do what you're looking for?

code:
beer_groups = @user.cellared_beers.count(:group => [:beer_id,:year,:size])
@beer_counts = 
  beer_groups.map do |values,count|
    beer = Beer.find(values[0])
    [beer.id, beer.name, beer.brewery.id, beer.brewery.name, beer.style, beer.abv, values[1], values[2], count]
  end

Smol fucked around with this message at 21:23 on May 15, 2013

raej
Sep 25, 2003

"Being drunk is the worst feeling of all. Except for all those other feelings."

Smol posted:

Ok, I think I understand your problem now. Does this do what you're looking for?

code:
beer_groups = @user.cellared_beers.count(:group => [:beer_id,:year,:size])
@beer_counts = 
  beer_groups.map do |values,count|
    beer = Beer.find(values[0])
    [beer.id, beer.name, beer.brewery.id, beer.brewery.name, beer.style, beer.abv, values[1], values[2], count]
  end

Woo! Yes, that's exactly what I was looking for! Thank you!

Pardot
Jul 25, 2001




Isn't that going to do n+1 queries where n is how many beers they have?

Honestly, I'd just write a single raw sql query and skip active record entirely at this point. However I've been working on a postgres service for a few years now, so I might be crazy.

prom candy
Dec 16, 2005

Only I may dance
What is it that you're actually trying to do? Can you give me an example of the input that you've got and the output that you desire? Because yes, that's going to do n+1 queries and get awful slow.

raej
Sep 25, 2003

"Being drunk is the worst feeling of all. Except for all those other feelings."

prom candy posted:

What is it that you're actually trying to do? Can you give me an example of the input that you've got and the output that you desire? Because yes, that's going to do n+1 queries and get awful slow.

Models are Users, Beers, Breweries, and Cellared_beers.

Breweries have many beers.
Users have many beers through cellared_beers.

The Beer model contains information on a kind of beer (Name, brewery, description, ABV, style, etc)
A Cellared_beer represents a physical bottle one owns and the attributes. (Size, year, etc)

A user can go to a beer page and "add to cellar" which asks for year and size of the beer to be added. This creates a cellared_beer with user_id, beer_id, year, size.

A user can go to his cellar and list all of the cellared_beers, but grouped by similar size and dates.

Output would look like:
code:
Name      | Brewery   | ABV  | Style       | Size | Year | Amount
Bud Light | Budweiser | 4.2% | Light Lager | 12oz | 2013 | 18
Bud Light | Budweiser | 4.2% | Light Lager | 22oz | 2013 | 3
Bud Light | Budweiser | 4.2% | Light Lager | 12oz | 2012 | 6

Pardot
Jul 25, 2001




Ruby code:
ActiveRecord::Base.connection.raw_connection.exec(<<-SQL, [user_id])
select
  beers.name as name
, breweries.name as brewery
, beer.abv
, beer.style
, cellard_beers.size
, cellard_beers.year
, count(*) as amount
from cellard_beers
join beers on beers.id = cellard_beers.beer_id
join breweries on breweries.id = beers.breweries_id
where 
  cellard_beers.user_id = $1
group by 1,2,3,4,5,6
order by 7 desc
SQL

A MIRACLE
Sep 17, 2007

All right. It's Saturday night; I have no date, a two-liter bottle of Shasta and my all-Rush mix-tape... Let's rock.

Pardot posted:

Ruby code:

Cool, I've never seen this before. Thanks!

prom candy
Dec 16, 2005

Only I may dance
Pardot is obviously the master but I'd like to try my hand at writing that with AR:

code:
CellaredBeer.
  select('beers.name, breweries.name, beers.abv, beers.style, cellared_beers.size, cellared_beers.year, count(*) as amount').
  includes({:beer => :brewery}).
  where('cellared_beers.user_id = ?', current_user.id).
  group('1,2,3,4,5,6').
  order('amount DESC')
Is that about right? I like to avoid writing raw SQL where I can.

manero
Jan 30, 2006

prom candy posted:

Pardot is obviously the master but I'd like to try my hand at writing that with AR:

code:

CellaredBeer.
  select('beers.name, breweries.name, beers.abv, beers.style, cellared_beers.size, cellared_beers.year, count(*) as amount').
  includes({:beer => :brewery}).
  where('cellared_beers.user_id = ?', current_user.id).
  group('1,2,3,4,5,6').
  order('amount DESC')

Is that about right? I like to avoid writing raw SQL where I can.

Wrap it all up in a class method! :)

Cocoa Crispies
Jul 20, 2001

Vehicular Manslaughter!

Pillbug

DreadCthulhu posted:

If I'm understanding this correctly, the advantage of the signed cookie approach is that you don't have to have a server-side map of permissions/sessions, and you can effectively "distribute" the burden onto the clients? Keeping a properly synced user/permissions/sessions map in memory at all times and persisting it to db seems like extra work. I think some people use solutions like Redis for that as well.

HMAC is secure when you pick a quality secret. Rack's cookie session implementation that Rails uses SHA-1, which while it's too weak for passwords, are fine for data that isn't a human-generated (i.e. bad) password.

My understanding is that the cookie is just identity, and authorization for actions based on that identity lives in the app at runtime.

Syncing a user/session map between memory and database isn't hard, but expiring it can be, and if your app lives in multiple datacenters, that adds a whole new dimension of "fun" to database synchronization.

Lexicon
Jul 29, 2003

I had a beer with Stephen Harper once and now I like him.
In ruby, is there an easy way to tell at the point of execution whether "self" refers to a class or an instance? I'm debugging some meta-programming hell (that I didn't write) and self.extend is getting called on a class instead of an instance somehow, and causing class-wide definitions that I don't want to exist. Basically, I want the opportunity to insert in "debugger if self is a class" so I can see where it's being called from. Any thoughts?

Obsurveyor
Jan 10, 2003

Lexicon posted:

In ruby, is there an easy way to tell at the point of execution whether "self" refers to a class or an instance? I'm debugging some meta-programming hell (that I didn't write) and self.extend is getting called on a class instead of an instance somehow, and causing class-wide definitions that I don't want to exist. Basically, I want the opportunity to insert in "debugger if self is a class" so I can see where it's being called from. Any thoughts?

Doesn't the class method tell you want you need to know?

code:
self.class == Class

plasticbugs
Dec 13, 2006

Special Batman and Robin
I know this is a really stupid question, but what the heck.

I'm working with push notifications in my iOS app. Each notification needs its own unique identifier. The notifications are very ephemeral. They're created and pushed to a remote server (Urban Airship) from my Rails server in one step, so I don't need to store a notification object on my Rails server. I just need to assign the notifications a unique ID when they're created just before they're pushed.

My thought was to just create a Notification model and give it no attributes. Then, every time the Rails app creates a new notification to push, it will also create and save a new Notification instance, which will auto-increment its id and assign the object's id to the notification's unique identifier (UA calls these aliases).

This sounds like a dumb way to create a counter. If my app is successful, it's going to fill my database with tens of thousands of empty records over the lifetime of the app.

Is there a cleaner, more pragmatic way to create a counter like this that also avoids race conditions?

The Journey Fraternity
Nov 25, 2003



I found this on the ground!

plasticbugs posted:

I know this is a really stupid question, but what the heck.

I'm working with push notifications in my iOS app. Each notification needs its own unique identifier. The notifications are very ephemeral. They're created and pushed to a remote server (Urban Airship) from my Rails server in one step, so I don't need to store a notification object on my Rails server. I just need to assign the notifications a unique ID when they're created just before they're pushed.

My thought was to just create a Notification model and give it no attributes. Then, every time the Rails app creates a new notification to push, it will also create and save a new Notification instance, which will auto-increment its id and assign the object's id to the notification's unique identifier (UA calls these aliases).

This sounds like a dumb way to create a counter. If my app is successful, it's going to fill my database with tens of thousands of empty records over the lifetime of the app.

Is there a cleaner, more pragmatic way to create a counter like this that also avoids race conditions?

https://rubygems.org/gems/uuid

Pardot
Jul 25, 2001




Yeah I'd go the UUID route if you can. If you reallllllly need incrementing ones you can just create a raw sequence. http://www.postgresql.org/docs/9.2/static/functions-sequence.html

code:
will=# create sequence heysup;
CREATE SEQUENCE
Time: 17.725 ms
will=# select nextval(heysup);
ERROR:  column "heysup" does not exist
LINE 1: select nextval(heysup);
                       ^
Time: 2.227 ms
will=# select nextval('heysup');
 nextval
---------
       1
(1 row)

Time: 3.958 ms
will=# select nextval('heysup');
 nextval
---------
       2
(1 row)

Time: 0.241 ms
will=# select nextval('heysup');
 nextval
---------
       3
(1 row)
You don't need an external gem though for ruby UUID generation:

Ruby code:
~ $ ruby -r securerandom -e 'p SecureRandom.uuid'
"cb7f89a5-e698-471a-8a4a-6ac007c7a66a"
~$ ruby -r securerandom -e 'p SecureRandom.uuid'
"538d3b76-c55a-41b9-9ce6-4c268e5b983e"

Pardot fucked around with this message at 07:36 on May 21, 2013

plasticbugs
Dec 13, 2006

Special Batman and Robin

Pardot posted:

Yeah I'd go the UUID route if you can.
...
You don't need an external gem though for ruby UUID generation:

Ruby code:
~ $ ruby -r securerandom -e 'p SecureRandom.uuid'
"cb7f89a5-e698-471a-8a4a-6ac007c7a66a"
~$ ruby -r securerandom -e 'p SecureRandom.uuid'
"538d3b76-c55a-41b9-9ce6-4c268e5b983e"

I didn't even know this was a thing. :monocle: Thanks guys!

Smol
Jun 1, 2011

Stat rosa pristina nomine, nomina nuda tenemus.
It was added in 1.9.

Cocoa Crispies
Jul 20, 2001

Vehicular Manslaughter!

Pillbug

Lexicon posted:

In ruby, is there an easy way to tell at the point of execution whether "self" refers to a class or an instance?

self.is_a? Class returns true if self is an instance of Class.

Ruby code:
5.is_a? Class
     # => false
5.is_a? Fixnum
     # => true
Fixnum.is_a? Class
     # => true

Lexicon
Jul 29, 2003

I had a beer with Stephen Harper once and now I like him.

Cocoa Crispies posted:

self.is_a? Class returns true if self is an instance of Class.

Ruby code:
5.is_a? Class
     # => false
5.is_a? Fixnum
     # => true
Fixnum.is_a? Class
     # => true

Perfect, thanks!

raej
Sep 25, 2003

"Being drunk is the worst feeling of all. Except for all those other feelings."
In reference to my cellar list above. How would I go about destroying a Cellared_Beer with the correct variables (size, year) when this is being viewed in the User model?

For instance, the view attached is users/1/cellar

I need the "delete" link to destroy a cellared_beer (which has user_id, beer_id, size, year, created_at, updated_at) that matches that line item (unique on beer_id, size, year)

Only registered members can see post attachments!

Vulture Culture
Jul 14, 2003

I was never enjoying it. I only eat it for the nutrients.

raej posted:

In reference to my cellar list above. How would I go about destroying a Cellared_Beer with the correct variables (size, year) when this is being viewed in the User model?

For instance, the view attached is users/1/cellar

I need the "delete" link to destroy a cellared_beer (which has user_id, beer_id, size, year, created_at, updated_at) that matches that line item (unique on beer_id, size, year)


Using the approach you've chosen, you're overcomplicating things and making your schema really difficult to work with -- if you decide to modify your constraints anywhere in the system, you have lots of things you need to update because of the incredibly tight coupling you've chosen. If I were you, I'd create a single numeric primary key for each combination of (beer_id, size, year) and use simple unique constraints instead of a compound primary key to ensure uniqueness properly.

raej
Sep 25, 2003

"Being drunk is the worst feeling of all. Except for all those other feelings."

Misogynist posted:

Using the approach you've chosen, you're overcomplicating things and making your schema really difficult to work with -- if you decide to modify your constraints anywhere in the system, you have lots of things you need to update because of the incredibly tight coupling you've chosen. If I were you, I'd create a single numeric primary key for each combination of (beer_id, size, year) and use simple unique constraints instead of a compound primary key to ensure uniqueness properly.

Well, each cellared_beer has a unique key... The problem I was having was grouping like beers for display in a cellar. If someone adds a 6-pack of something, I'd rather not have 6 lines for that beer. But I need to be able to decriment that amount when someone decides to drink one of those beers.

Cocoa Crispies
Jul 20, 2001

Vehicular Manslaughter!

Pillbug

raej posted:

Well, each cellared_beer has a unique key... The problem I was having was grouping like beers for display in a cellar. If someone adds a 6-pack of something, I'd rather not have 6 lines for that beer. But I need to be able to decriment that amount when someone decides to drink one of those beers.

On your CellaredBeer model, add a #drink method that decrements the quantity and updates drank_at. If the quantity is zero, keep it around so the user doesn't have to rack their brain over what that one beer they had last month was.

raej
Sep 25, 2003

"Being drunk is the worst feeling of all. Except for all those other feelings."

Cocoa Crispies posted:

On your CellaredBeer model, add a #drink method that decrements the quantity and updates drank_at. If the quantity is zero, keep it around so the user doesn't have to rack their brain over what that one beer they had last month was.

So would it be better to style cellared_beers as id, user_id, beer_id, year, size, amount? Then be able to lower amount every time a beer is removed?

How would that work when say someone buys a 6 pack, then a week later, buys another 6 pack and hasn't drank any? Wouldn't that be 2 lines of 6?

Nybble
Jun 28, 2008

praise chuck, raise heck
I think you need to zoom out a little. What exactly are you trying to measure? Are you trying to measure number of bottles or number of packages? If you had a 6 pack and a 12 pack, what do YOU want to display? 18, 1/6 and 1/12, or both of those options?

That'll change how you model it, and right now I'm not exactly clear on which you'd like.

xtal
Jan 9, 2011

by Fluffdaddy

Lexicon posted:

In ruby, is there an easy way to tell at the point of execution whether "self" refers to a class or an instance? I'm debugging some meta-programming hell (that I didn't write) and self.extend is getting called on a class instead of an instance somehow, and causing class-wide definitions that I don't want to exist. Basically, I want the opportunity to insert in "debugger if self is a class" so I can see where it's being called from. Any thoughts?

Pedantry: everything in Ruby is an instance. :) Fixnum.is_a?(Class) is true not because Fixnum is a class per se, but because Fixnum is literally an instance of Class.

raej
Sep 25, 2003

"Being drunk is the worst feeling of all. Except for all those other feelings."

Nybble posted:

I think you need to zoom out a little. What exactly are you trying to measure? Are you trying to measure number of bottles or number of packages? If you had a 6 pack and a 12 pack, what do YOU want to display? 18, 1/6 and 1/12, or both of those options?

That'll change how you model it, and right now I'm not exactly clear on which you'd like.

I want to keep track of the number of like bottles based on beer, year, and size. The 6-pack analogy was just knowledge that most 12oz bottles come in a 6-pack, and a person would be adding many of a like bottle based on that.

Cocoa Crispies
Jul 20, 2001

Vehicular Manslaughter!

Pillbug

raej posted:

So would it be better to style cellared_beers as id, user_id, beer_id, year, size, amount? Then be able to lower amount every time a beer is removed?

How would that work when say someone buys a 6 pack, then a week later, buys another 6 pack and hasn't drank any? Wouldn't that be 2 lines of 6?

Add a Beer#buy(user, quantity) or User#buy(beer, quantity) method that handles the finding/creating and incrementing.

CellaredBeer might belongs_to :user, belongs_to :beer, and have a quantity, size/distribution (i.e. 12oz can, 12oz bottle, 40oz can), bought_at, drank_at, etc.

Lexicon
Jul 29, 2003

I had a beer with Stephen Harper once and now I like him.

xtal posted:

Pedantry: everything in Ruby is an instance. :) Fixnum.is_a?(Class) is true not because Fixnum is a class per se, but because Fixnum is literally an instance of Class.

As a fellow pedant, thanks for putting me straight :)

raej
Sep 25, 2003

"Being drunk is the worst feeling of all. Except for all those other feelings."

Cocoa Crispies posted:

Add a Beer#buy(user, quantity) or User#buy(beer, quantity) method that handles the finding/creating and incrementing.

CellaredBeer might belongs_to :user, belongs_to :beer, and have a quantity, size/distribution (i.e. 12oz can, 12oz bottle, 40oz can), bought_at, drank_at, etc.

Can you enlighten me as to what this is called so that I can read up on it more? This sounds like the ticket!

Adbot
ADBOT LOVES YOU

Cocoa Crispies
Jul 20, 2001

Vehicular Manslaughter!

Pillbug

raej posted:

Can you enlighten me as to what this is called so that I can read up on it more? This sounds like the ticket!

It's called object oriented design: you put methods on objects that match your domain so instead of computer bullshit they're a domain model.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply