Active Admin rails, how to escape html before save? - ruby-on-rails

i'm new of rails and since few days i'm playing with active admin.
I'm using it to manage data of an old legacy system.
I have a issue: i need to save an html string into table, but escaped and i dont find a solution for this.
Example, i want to save this
<b>Ciao</b> mondo!
Like that
<p>Ciao <b>Mondo!</p>
With this block of code i can show it correctly in index page, but when i try to add new or edit it doesn't excape correctly
index do
column :label
column (:value_it) { |e| raw(e.value_it) }
column (:value_en) { |e| raw(e.value_en) }
column (:value_es) { |e| raw(e.value_es) }
default_actions
end
Thanks

irb(main):001:0> CGI.escapeHTML '<b>Ciao</b> mondo!'
=> "<b>Ciao</b> mondo!"
irb(main):002:0> CGI.unescapeHTML( CGI.escapeHTML '<b>Ciao</b> mondo!' )
=> "<b>Ciao</b> mondo!"
plug it into before_save hook on the model and you're good to go

Related

How to validate input which depends on checkbox

I recently started with rails.
I have one task here, but I don't know what is best practice and how to do it.
I have form with checkbox currency? and input currency_code.
Only value currency_code will be stored in database.
What I need:
1. If checkbox currency? is TRUE => currency_code must be filled
2. If checkbox currency? is FALSE => currency_code will be reset to nil
How to validate 1. if currency? is not in database (table column) so model does not know about this?
In case 2. Where I should check this and reset value currency_code to nil?
For case 2. I have this in my controller, but I don't like. I think that there must be a better solution.
def data_params
parameters = params.require(:data).permit(
:currency_code
)
parameters[:currency_code] = nil unless params[:data][:currency].to_bool
parameters
end
The attribute 'currency?' which is not part of the model is called virtual attributes. In Rails, we can use virtual attributes by setting
attr_accessor :currency?
in your corresponding_model.rb.
Now you can use this 'currency?' attribute in your form like other model attributes.
For case 2, the plcaement for this kind of data validations is to validate them in the view before even coming into the model. you must use jquery / javascript or any script of your choice. Here I provide jQuery snippet.
If you are new for using jquery in rails app, follow this https://github.com/rails/jquery-rails
In your form_page.html.erb add ids to the html elements.
<%= f.check_box :currency?, id: 'currency_checkbox' %>
and
<%= f.text_field :currency_code, id: 'currency_code' %>
The jquery snippet
curreny_checkbox = $('#curreny_checkbox')
currency_code = $('#currency_code')
$(currency_checkbox).on('change', function(){
if(this.checked)
currency_code.val('2')
else
currency_code.val('')
})
In your controller, you can simply assign the values
def create
// other codes //
#obj.currency_code = params[:currency_code]
end
If you want to validate input on model level you should store the currency? in the database.
Still let say for some unexplained reasons you don't want to store currency? in you database(which I won't suggest you in any case). You can define a method in model.
def set_currency_if_required is_currency_required
self.currency_code = nil unless is_currency_required
end
in controller
def create
model = Model.new(data_params)
model.set_currency_if_required(params[:data][:currency].to_bool)
model.save
end
...
def data_params
parameters = params.require(:data).permit(
:currency_code
)
end
this way you will have better readability and a clear idea about whats going on with the code.

Accessing HSTORE data in rails controller

So I set up a postgres server and have it working with hstore values.
As of right now, I have a table books, structured with
name:string data:hstore
I have created a sample entry to test:
Book.create(:name => "My First Book", :data => {'author' => 'Kevin', 'pages' => 368})
I have loaded the data into a variable:
#book = Book.where("data ? :key", :key => 'pages')
(just to test, i realize this query would serve no real purpose...)
I print the data as JSON and this works fine, the entry is found and displayed. However, what I am trying to do is access, say the pages, an hstore value. I did some research and found
#book.data['pages']
However, when i try to run this, I get
undefined method `data' for #<Book::ActiveRecord....
Any and all help is greatly appreciated!
The Active Record where will give you an array even if there is only 1 value.
You can do
#book = Book.where("data ? :key", :key => 'pages')[0]
to get that record
and then
#book.data
will work as desired.
If you might get multiple records and just using the first found is ok you could also use:
#book = Book.where("data ? :key", :key => 'pages').first
#book.data
or just
#book = Book.where("data ? :key", :key => 'pages').first.data
After fiddling around, i found that I simply needed to call:
#book[0].data

Returning a virtual attribute in a select query

Part of an application I'm building is an API. Recent changes mean that I need to put two different versions of the data into my json feed. I think the best way to do this is to make the necessary changes in the database then create a virtual attribute to concatenate the data.
In my model I have the event_summary virtual attribute which there's no issue with outputting in views using <%= #event.event_summary =>:
def event_summary
"#{title} (#{start_datetime.strftime('%A %d %b, %l:%M%P')})"
end
In my API controller I have a select query which gets the attributes I need for the API response (simplified version here):
respond_to :json
def index
respond_with Event.select('title, event_summary')
end
The problem is that it always returns an undefined column error:
PG::UndefinedColumn: ERROR: column "event_summary" does not exist LINE 1: SELECT title, event_summary FROM "events"
I also tried the following but got the same result:
respond_with Event.select('title', :event_summary)
I'm using Postgres if that makes any difference.
Is there a way to do this?
Thanks!
You can't use virtual attributes in the select method because it will be turned into a SQL statement and that field doesn't exist in your table. You could however, do the concatenation and date formatting in SQL:
Event.select('title, (title || ' ' || to_char(start_datetime, 'HH12:MI:SS')) as event_summary')
That will in effect create a "virtual attribute" but in sql land and it will return events with that attribute present and formatted by the to_char postgres method. The date formatting isn't exactly what you had, so you'll need to tweak it to your needs (by changing the format string 'HH12:MI:SS') as detailed in the docs here: http://www.postgresql.org/docs/8.2/static/functions-formatting.html
Hope that helps.
I think this might do what you want:
def index
render :json => Event.all.to_json :methods => :event_summary
end
[EDIT]
IIRC respond_with doesn't work with to_json, so you have to use render

How to column sort using will_paginate where the data is a record array, not a model

I have a service I query and I get data I filter through and create a an array of records.
Unless I missed something, ActiveResource::Base does not qualify since the access to the service is not via rest and I can't use the raw data as delivered.
I am displaying the data in a table and use will_paginate to page the data. But I am not currently married to will_paginate.
I do need to sort the columns as well as paginate.
I have found two version of ujs_sort_helper.
https://github.com/pengwynn/ujs_sort_helper
https://github.com/sikachu/ujs_sort_helper
I am trying to understand:
- http://javathehutt.blogspot.com/2009/06/mo-simple-sortable-tables-in-rails.html
What have other done in rails 3? Or is one of the ujs_sort_helper packages just he correct way to go.
In term of data refresh, this is a dashbaord. Multiple data source will address the various DIVs.
Also, I am a Rails noob. But not a programming noob.
You could use meta_search's sort_link if you wish.
I like it because it also does filtering incredibly easy with meta_where.
You can also make the behavior through ajax by adding the data-remote attribute to 'a.sort_link' (i have done that through javascript).
I would welcome the maintainer of ujs_sort_helper to comment. Just a bug here and there in the rails 3 version of the code. Now ujs_sort_helper works, for me.
What I have not done is create ANOTHER branch on this package. I emailed the file to the author.
sort order now compares symbols, instead of symbol to string.
def sort_order(column, initial_order='asc')
#safe since to_sm on a sym is a nil operation. At least for now.
if session[#sort_name][:key].to_sym == column.to_sym
session[#sort_name][:order].downcase == 'asc' ? 'desc' : 'asc'
else
initial_order
end
end
The icon us set via the current order value. The sort clause should be the opposite. So show down arrow for the list being displayed in ascending order, but the 'url' is set to redisplay the table in descending order.
I have no clue what the :q symbol is supposed to be used for.
def sort_header_tag(column, options = {})
options[:initial_order].nil? ? initial_order = "asc" : initial_order = options[:initial_order]
key = session[#sort_name][:key].to_sym
order = sort_order(column, initial_order)
caption = options.delete(:caption) || column.to_s.titleize
url = { :sort_key => column, :sort_order => order, :filter => params[:filter]}
url.merge!({:q => params[:q]}) unless params[:q].nil?
content_tag('th', link_to(caption, url, :class=>session[#sort_name][:order] ), :class => "sort_link #{order if key == column}")
end

Get two random elements from a RoR model

I'm trying to use RoR for something simple and I'm having some trouble picking up the basics. My closest background is ASP.NET MVC but I'm finding all of the RoR tutorials focus on what rails is really good at (scaffold stuff) but not how to make your own actions and get them to do stuff with parameters etc. (something trivial in ASP.NET MVC).
At the moment I am trying to get two random elements out of the model.
I think I'm dealing with an ActiveRecord collection of some sort?
I have read that there is a .rand method somewhere on collections/arrays, although other places suggest that rand is just a method for getting a random number up to a certain count. I can't even get the following code to work:
def index
#items = Array.new(Item[0], Item[0])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #domain }
end
end
Anything that can help with this, and ideally help with further patching from ASP.NET MVC to RoR would be really appreciated.
To retrieve two random items from an ActiveRecord model:
#things = Thing.all(:order => 'RANDOM()', :limit => 2)
If you want 2 random items from the database, then ask the database for 2 random items:
#items = Item.find(:all, :limit => 2, :order => "RANDOM()")
There's no point loading all of the Items from your system if you're only using 2, that's a waste.
If you do already have an array from somewhere else that you need to get random values from, then Rails adds a rand method to the Array class:
#items = [my_arr.rand, my_arr.rand]
I don't know what you were trying to do with Item[0] but that doesn't do anything meaningful in Rails.
What does your model look like? I'm not sure what you're trying to do with Item[0] there. For randomizing your array you could do something like this:
#items = ["item1", "item2", "item3"].sort_by {rand}
then you could just do #items[0] and #items[1] to get 2 items of the randomized array.
As for params, you can get any form variables or request params from the query string by using the params hash:
params[:user]
The symbol name is just the name of the form field or param in the query string.
Rails controllers usually contain one or more restful actions (index, show, new, create, delete, edit, update) if you've routed it as a resource, but you adding your own actions involves just adding a new method to your controller, routing that action in the routes.rb, and creating a view with with the name of that action.
More info on your model & what you are trying to accomplish would help, but if you are trying to pull a random record from a database like sqlite, you can do something like:
#item = Items.find(:first, :order => 'RANDOM()')
Where Items is your model class. The 'RANDOM()' is just a string handed to the database to tell it how to sort, so you'll have to adjust to match whatever database you're using.
With a Mysql Database use RAND() and not RANDOM()
#items = Item.find(:all, :limit => 2, :order => "RAND()")

Resources