2011-07-21 15 views
11

Oto mój problem.Interpolacja łańcuchów znaków w łańcuchu z bazy danych

Chcę pobrać ciąg przechowywany w modelu iw czasie wykonywania zmienić jego część za pomocą zmiennej z aplikacji szyny. Oto przykład:

Mam model wiadomości, którego używam do przechowywania kilku unikatowych wiadomości. Tak różni użytkownicy mają ten sam komunikat, ale chcę, aby być w stanie pokazać swoje nazwisko w środku wiadomości, np

"Hi #{user.name}, ...." 

Próbowałem przechowywać dokładnie, że w bazie danych, ale robi się uciec przed pokazaniem się widok lub zostaje interpolowany podczas przechowywania w bazie danych za pośrednictwem konsoli szyn.

Z góry dziękuję.

Odpowiedz

9

Jeśli chcesz

"Hi #{user.name}, ...." 

w swojej bazie danych, należy użyć apostrofów lub uciec # z backslashem zachować Ruby od interpolacji #{} rzeczy od razu:

s = 'Hi #{user.name}, ....' 
s = "Hi \#{user.name}, ...." 

Później, kiedy chcesz zrobić interpolację, którą mógłbyś, gdybyś się śmiał lub zaufał sobie, używaj eval:

s = pull_the_string_from_the_database 
msg = eval '"' + s + '"' 

Zauważ, że aby eval działał, musisz zmienić s w podwójny cudzysłów. To zadziała, ale nie jest to najmilsze podejście i pozostawia cię otwartymi na wszelkiego rodzaju dziwne i mylące błędy, ale powinno być w porządku tak długo, jak ty (lub inni zaufani ludzie) piszesz struny; Myślę, że będziesz lepiej z prostego systemu mikro-szablonów, nawet coś tak prostego jak to:

def fill_in(template, data) 
    template.gsub(/\{\{(\w+)\}\}/) { data[$1.to_sym] } 
end 
#... 
fill_in('Hi {{user_name}}, ....', :user_name => 'Pancakes') 

Można użyć cokolwiek ograniczniki chciał oczywiście pojechałem z {{...}} ponieważ używam Mustache.js i Handlebars.js ostatnio. Ta naiwna implementacja ma problemy (brak opcji formatowania w szablonie, brak separatora, ...), ale może wystarczyć; Jeśli twoje szablony stają się bardziej skomplikowane, możesz chcieć przechowywać tylko bity o wartości ERB w bazie danych i użyć procesora ERB w standardowej ofercie biblioteki.

+0

Dzięki, że działało ... Już przechowywałam pojedynczy cytowany ciąg znaków. Właśnie brakowało mi sposobu interpolacji po pobraniu go z bazy danych. Jestem świadomy ryzyka bezpieczeństwa związanego z używaniem tego, ale użytkownicy nie mogą bezpośrednio zmienić tego ciągu. –

+0

Dodam, że jeśli twój ciąg zawiera HTML, użyj metody 'raw' (http://apidock.com/rails/ActionView/Helpers/OutputSafetyHelper/raw) kontra metody' html_safe'. – dennismonsewicz

0

jeden sposób mogę myśleć robi to mieć szablonów przechowywanych na przykład:

„hi nazwa”

wtedy funkcję w modelach, które po prostu zastępuje znaczniki szablonu (nazwa) z przekazany argumenty. Może to być również użytkownik zalogowany.

Ponieważ ta nowa funkcja będzie częścią modelu, można jej użyć jako kolejnego pola modelu z dowolnego miejsca w szynach, w tym pliku html.erb.

Mam nadzieję, że pomoże, daj mi znać, jeśli potrzebujesz więcej opisu.

+0

I get it, myślę, że to działa, problem widzę w tym jest to, że będę musiał określić wszystkie możliwe tagów można używać i mapować każdy jeden do odpowiednich zmiennych/funkcji wewnątrz aplikacji. Pomyślałem tylko, że będzie prostszy sposób robienia tego, jak interpolacja dla normalnego ciągu znaków. –

+0

Myślę, że twoje podejście też powinno działać. Można uniknąć tworzenia się interpolowanej ciągi przed jej zapisaniem w bazie danych, tworząc ciąg znaków za pomocą pojedynczych cudzysłowów zamiast podwójnych cudzysłowów. Nie jestem pewien, dlaczego uciekł przed zobaczeniem. – Shaunak

+0

Przechowywałem pojedynczą cytowaną wersję, ale przed zapisaniem w bazie danych zostanie ona przekształcona w łańcuch znaków podwójnego cudzysłowu. –

34

Nie widzę powodu, aby zdefiniować niestandardowe funkcje pomocnika ciągu. Ruby oferuje very nice formatting approaches, np.:

"Hello %s" % ['world'] 

lub

"Hello %{subject}" % { subject: 'world' } 

obu przykładach powrócić "Hello World".

+5

To jest najbardziej eleganckie i proste rozwiązanie problemu. – januszm

+1

Zgadzam się. Jest to najprostsze rozwiązanie wykorzystujące istniejącą funkcjonalność. – CDub

0

dodając kolejne możliwe rozwiązanie wykorzystujące Procs:

#String can be stored in the database 
string = "->(user){ 'Hello ' + user.name}" 

proc = eval(string) 

proc.call(User.find(1)) #=> "Hello Bob" 
Powiązane problemy