Forum: Italian Ruby user group DB view

0d4857c0bd9540f743afc22758a06c46?d=identicon&s=25 FleX (Guest)
on 2013-11-10 18:40
(Received via mailing list)
Avrei bisogno di creare l'equivalente di una vista db estendendo un
model con una serie di campi "calcolati" da altri model.
Sono riucito a farlo mediante l'aggiunta di un def ad un model
esistente. Il campo custom viene valorizzato correttamente, ma non
riesco ad usarlo come se fosse un vero e proprio campo, con chiamate
tipo:
Mymodel.find(:all, :order => "customfield desc")

Sapreste suggerirmi una soluzione ?

--
FleX
[Linux User #347703 PGP Key ID: 98AA9D3E
FingerPrint: 7D25B 0CE4 898A 22CB F765  E2A5 88B7 4C5C 98AA 9D3E]
Cb8e3a1650513848561ca38f84399fa1?d=identicon&s=25 Fabrizio Regini (freegenie)
on 2013-11-10 19:19
(Received via mailing list)
Devi produrre i campi aggiuntivi, quelli che chiami 'calcolati', nel
database, tramite una vista SQL oppure l'aggiunta di colonne calcolate
tramite il metodo `select` di AR.

Esempio

Mymodel.select("a, b, a + b AS c")

In questo caso la colonna "c" non esiste veramente nel database, ma
l'avrai
comunque tra gli attributi di ogni istanza di AR.

Per l'ordinamento a questo punto puoi fare:

Mymodel.select("a, b, a + b AS c").order("(a + b) DESC")

E' l'unico modo che hai per poter ottenere i record ordinati
direttamente
dalla query SQL, cosa che ti consiglio caldamente di perseguire sempre e
comunque. Perch, per dirne una, ti consente di avere una paginazione con
una delle numerose gem tipo will_paginate.




2013/11/10 FleX <flex@programmareweb.com>
0d4857c0bd9540f743afc22758a06c46?d=identicon&s=25 FleX (Guest)
on 2013-11-10 20:51
(Received via mailing list)
On 11/10/2013 07:19 PM, Fabrizio Regini wrote:
> Devi produrre i campi aggiuntivi, quelli che chiami 'calcolati', nel
> database, tramite una vista SQL
associando un model per la vista ?

> oppure l'aggiunta di colonne calcolate
A questo ci avevo pensato, ma non volevo inserire query in sql molto
complesse all'interno del controller dato che al momento ero riuscito a
manipolare tutti i dati usando i metodi.

--
FleX
[Linux User #347703 PGP Key ID: 98AA9D3E
FingerPrint: 7D25B 0CE4 898A 22CB F765  E2A5 88B7 4C5C 98AA 9D3E]
Cb8e3a1650513848561ca38f84399fa1?d=identicon&s=25 Fabrizio Regini (freegenie)
on 2013-11-10 20:56
(Received via mailing list)
Infatti non lo devi fare nel controller. Consiglio di fare un metodo di
classe che restituisce una relation, o uno scope.

class Mymodel

   def self.my_select
      select("a,b, a + b AS c").order("(a+b) DESC")
   end

end

Mymodel.my_select.count
Mymodel.my_select.limit(10)
@my_collection = Mymodel.my_select

etc etc etc.




2013/11/10 FleX <flex@programmareweb.com>
0d4857c0bd9540f743afc22758a06c46?d=identicon&s=25 FleX (Guest)
on 2013-11-11 11:12
(Received via mailing list)
On 11/10/2013 08:56 PM, Fabrizio Regini wrote:
> Infatti non lo devi fare nel controller. Consiglio di fare un metodo di
> classe che restituisce una relation, o uno scope.
>
> class Mymodel
>
>    def self.my_select
>       select("a,b, a + b AS c").order("(a+b) DESC")
>    end
>
> end

Ottimo, ci sono riuscito, ma senza far a meno di usare RAW sql. Sotto il
mio metodo:

def self.best_avg_prices(n)
    self.find_by_sql "SELECT mymodel.*, avg(prices.rating) as avgrating
    FROM mymodel, prices WHERE mymodel.id = prices.mymodel_id GROUP
    BY mymodel.id ORDER BY avgrating DESC LIMIT " + n.to_s + ";"
end

(Sono sicuro che e' migliorabile)
--
FleX
[Linux User #347703 PGP Key ID: 98AA9D3E
FingerPrint: 7D25B 0CE4 898A 22CB F765  E2A5 88B7 4C5C 98AA 9D3E]
Cb8e3a1650513848561ca38f84399fa1?d=identicon&s=25 Fabrizio Regini (freegenie)
on 2013-11-11 11:26
(Received via mailing list)
AAHHHHRRGGGG!

Ma sei impazzito???!! :)

>  BY mymodel.id ORDER BY avgrating DESC LIMIT  + n.to_s + ;"

Mai interpolare le stringhe SQL con delle variabili in quel modo, a meno
che non sei strasicuro della loro fonte.
In generale  meglio tenere vicino allinterpolazione anche la
dichiarazione di controllo sulla variabile, cos  sicuro che non te la
perdi.
Se per esempio n  un valore che prendi da params e passi dentro cos com
ti sei calato praticamente le braghe dal punto di vista della sicurezza.
SQL injection.
4beb0572f440ca9e9613126d4cbcf917?d=identicon&s=25 Massimo Maino (Guest)
on 2013-11-11 11:28
(Received via mailing list)
In data lunedì 11 novembre 2013 11:25:43, Fabrizio Regini ha scritto:
> da params e passi dentro così com’è ti sei calato praticamente le braghe
> http://lists.ruby-it.org/mailman/listinfo/ml
dove n è "1 UNION ALL SELECT username, password, whatever FROM users;"
:P


- Massimo Maino aka maintux -
*GitHub*: https://github.com/maintux[1]
*LinkedIn*: http://www.linkedin.com/in/maintux[2]
0d4857c0bd9540f743afc22758a06c46?d=identicon&s=25 FleX (Guest)
on 2013-11-11 11:35
(Received via mailing list)
On 11/11/2013 11:25 AM, Fabrizio Regini wrote:
> Mai interpolare le stringhe SQL con delle variabili in quel modo, a meno che non
sei strasicuro della loro fonte.

tranquilli: la variabile viene valorizzata staticamente nel controller,
non ha niente a che vedere con params.
A dirla tutta l'ho messa nel model perche' quando al metodo appendevo un
.limit(n) mi restituiva un bel undefined method `limit' for #<Array
e non volevo fare ulteriori conversioni.

--
FleX
Success is the maximum utilization of the ability that you have
[Linux User #347703 PGP Key ID: 98AA9D3E
FingerPrint: 7D25B 0CE4 898A 22CB F765  E2A5 88B7 4C5C 98AA 9D3E]
Cb8e3a1650513848561ca38f84399fa1?d=identicon&s=25 Fabrizio Regini (freegenie)
on 2013-11-11 11:59
(Received via mailing list)
Non sei obbligato ad usare i metodi di AR tipo select, limit, joins etc
anche se spesso  preferibile.
Ad ogni modo, anche se sei strasicuro della sorgente dei quella
variabile io ci applicherei uno dei tanti filtri che AR usa
internamente, anche solo come esercizio.

http://api.rubyonrails.org/classes/ActiveRecord/Co...

santizie_limit(n)

(non ricordo se richiede un namespace, ma ci siamo capiti)
0d4857c0bd9540f743afc22758a06c46?d=identicon&s=25 FleX (Guest)
on 2013-11-11 14:38
(Received via mailing list)
On 11/11/2013 11:58 AM, Fabrizio Regini wrote:
> Non sei obbligato ad usare i metodi di AR tipo select, limit, joins etc anche se
spesso  preferibile.
> Ad ogni modo, anche se sei strasicuro della sorgente dei quella variabile io ci
applicherei uno dei tanti filtri che AR usa internamente, anche solo come
esercizio.
>
>
http://api.rubyonrails.org/classes/ActiveRecord/Co...
>
> santizie_limit(n)
>
> (non ricordo se richiede un namespace, ma ci siamo capiti)
>

sicuramente non fa male, modifica fatta .
Grazie come al solito per i preziosi aiuti.

--
FleX
Success is the maximum utilization of the ability that you have
[Linux User #347703 PGP Key ID: 98AA9D3E
FingerPrint: 7D25B 0CE4 898A 22CB F765  E2A5 88B7 4C5C 98AA 9D3E]
Fb4482bd900141ed8bd3f3fcc3723f90?d=identicon&s=25 Luca Mearelli (Guest)
on 2013-11-11 20:08
(Received via mailing list)
2013/11/11 FleX <flex@programmareweb.com>
>
> A dirla tutta l'ho messa nel model perche' quando al metodo appendevo un
> .limit(n) mi restituiva un bel undefined method `limit' for #<Array
> e non volevo fare ulteriori conversioni.


il pregio di una soluzione fatta attraverso uno scope rispetto al
cablare
la query SQL in un metodo e' proprio che potresti poi usare tutti gli
altri
metodi di active record. Senza sapere di preciso il tuo data model, a
occhio:

def self.best_avg_prices(n)
    self.find_by_sql "SELECT mymodel.*, avg(prices.rating) as avgrating
    FROM mymodel, prices WHERE mymodel.id = prices.mymodel_id GROUP
    BY mymodel.id ORDER BY avgrating DESC LIMIT " + n.to_s + ";"
end

potrebbe tradursi in un:

scope :best_avg_price, select("mymodel.*, avg(prices.rating) as
avgrating").joins(:prices).group("mymodel.id")

nell-ipotesi che MyModel has_many :prices

altrimenti potresti sostituire la chiamata a joins con joins(%{join
prices
on prices.mymodel_id = mymodel.id})

nota bene come lo scope NON include la order by e NON include la limit
perche' poi lo userai soci:

MyModel.best_avg_price.order("avgrating DESC").limit(n)

N.B. il codice e' solo per dare un'idea l'ho scritto al volo eh :-)

ciao,
Luca
0d4857c0bd9540f743afc22758a06c46?d=identicon&s=25 FleX (Guest)
on 2013-11-12 10:06
(Received via mailing list)
On 11/11/2013 08:08 PM, Luca Mearelli wrote:
> scope :best_avg_price, select("mymodel.*, avg(prices.rating) as
> avgrating").joins(:prices).group("mymodel.id")

Perfetto, questo e' molto piu' versatile e pulito della soluzione
precedente (unico lieve difetto e' che non restistuisce il count)
Interessanti gli scope: non li avevo mai utilizzati

--
FleX
Success is the maximum utilization of the ability that you have
[Linux User #347703 PGP Key ID: 98AA9D3E
FingerPrint: 7D25B 0CE4 898A 22CB F765  E2A5 88B7 4C5C 98AA 9D3E]
This topic is locked and can not be replied to.