Search Amazon.com:
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 $3,400 per month for bandwidth bills alone, and since we don't believe in shoving popup ads to our registered users, we try to make the money back through forum registrations.
«106 »
  • 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 May 8, 2013 around 20:39

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

u mad, brah?


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
2 + 2 != 5

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

Yeah, yeah, yeah
Village...

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

Yeah, yeah, yeah
Village...

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 May 15, 2013 around 20:23

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

best alliance in hip-hop, waiyyohhh

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

best alliance in hip-hop, waiyyohhh

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!

Adbot
ADBOT LOVES YOU

Cocoa Crispies
Jul 20, 2001

Vehicular Manslaughter!



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.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply
«106 »