Restricting specific words on a form | ruby on rails - ruby-on-rails

I'm implementing a comment section on my blog and was wondering if there was a way to prevent users from submitting a name such as admin or [company name] to prevent people from trolling or otherwise wrong-doing.
I am using this REGEX to validate emails making sure they are properly formatted: VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
I'm just not sure if this is the same approach I need to be taking or if there are built in ways to prevent specific strings from being entered into a form input.
Thanks in advance for any help!

There are several ways you could do this, depending on how you want your front-end to behave. The simplest way would be to do the validation in the front-end, either with simple HTML-5 form validation, or with javascript. For HTML-5 validation you can use the pattern attribute on an input type="text" (which you could use a text_field_tag to generate in rails). This attribute accepts a regex as it's value, which you could use to prevent the input of certain key-words. You can read more about this here https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Form_validation
You could also do the validation in the back-end, either in the controller directly (hard to say what exactly you need but something like as a simple example)
if (params[:my_input_form].split & bad_words_array).any?
flash[:error] = "you entered a bad word"
redirect_to the_same_page_path
end
note: the & in this context is giving the intersection of the two arrays and will return a non-empty array if there is at least one element in common between the arrays (in this case, if any of the words entered in your input are in the bad_words array).
If you want to do it in the back-end and it's more complicated I would probably move the validation into the model as a custom validator.

You can use gem obscenity. It gives you ability to specify black list words and they'll be replaces with [censored] string

An alternative to what has already been proposed is to create a custom validation on your model with a regular expression.
For example:
validate :bad_words
def bad_words
if (/admin|sony/i.match(self.name))
errors.add(:name, "contains a word not allowed")
end
end
You should generate a regular expression that suits your needs, but it is recommended to use the regexp i modifier to do a case-insensitive search
I hope it helps!

Related

Load model partly in Ruby On rails

guys! I'm trying to make right architecture decision:
I need to hide from user of my site some fields of other users by default. So not to bother with filtering the fields in views I want to not load those fields at all, like:
default_scope -> { select(column_names - FILTERED_PARAMS) }
the rest of fields should be loaded explicitly in special cases.
The problem is that once code refers to the missing fields nomethod error shows up. I tried to meta-program those fields but fruitless this far. It seems to me that this approach doesn't fit to the AR object life-cycle.
Have you ever implemented such functionality if so what pattern have you chosen?
From my experience the best decision would be not to filter these params on the query with select, but to filter what parameters are actually sent to the user. my_model.as_json (with given param filtering options) is a simple solution for that, but for more advanced uses I would advise Rabl gem
https://github.com/nesquena/rabl
That way you have more control over which params are returned even in very advanced cases in a model-view-controller manner.

Rails - best practice to store key/value hash

Here's my challenge. I have a key/value set that I want to tie to a model. These are my specific requirements:
I want the hash to be stored as a serialized JSON object in the model's table instead of in a separate table
I want to be able to pre-define the valid keys within the model itself
I want to be able to set a strong type for each key and automatically perform validations. I don't want to have to write validation functions for each individual attribute unless it needs a validation out of the basic data type scope.
I would LOVE to be able to magically access the attributes inside a form generator (f.input :my_key) and have the form generator recognize that :my_key is of type :boolean and create a checkbox instead of a generic text input. The same for other data types.
There are a few different ways to solve this problem, and lots of opinions for both. I read over this answer from 5 years ago:
Best approach to save user preferences?
It seems that many/most of those plugins have been abandoned. Anything else come out in the last 5 years that matches my criteria?
Your question is a bit open-ended, but as far as I can see your needs, they should be met with using Hashie gem.

Rails: Joining multiple temp fields before save

So basically I have a Book model that contains information like
book title (string)
author (string)
description (text)
etc.
Now on the front end I added the capability of dynamically adding more author fields. In the form I named it book[coauthor], so if I add a second author, I'd have a field book[coauthor][name_0].
What I'd like to achieve is combine book[author] and all book[coauthor][name_i] to one big string and separate each name with ,. (i.e. so with book[author] being "Alice" and book[coauthor][name_0] being "Bob" I should get "Alice,Bob" saved in book[author] in DB)
First Question: At this point is it better to do it with Javascript or with Rails (in controller)?
Second Questiion: Currently I'm doing it in the Rails controller but got Can't mass-assign protected attribute 'coauthor'. However I don't want to make it a real attribute since all I need is some processing before saving all the information to the author field. What should I do?
Thanks guys.
The first question is a bit loaded, and you might get some heated disagreements but the way I look at it is this. Not everybody runs with Javascript enabled, so I make sure I have a way to do everything through Rails myself.
In this case, it's actually quite easy.
The first thing I recommend is to not send the coauthors as part of the params[:book]. Instead, send them separately as a params[:coauthors]. Then in your controller you can do this:
#book = Book.new(params[:book])
#book.author = ([#book.author] + [params[:coauthors]]).join(",")
#book.save
Actually, it may be better to update params[:book][:author] since that would work for both create and update. Either way, I hope that helps.
To the first question: I don't see any compelling reason to one over the other. JavaScript might provide a bit more ability to validate/fix formatting in this field in 'real time', but I'm not sure that's particularly important.
To the second question: You don't need to make something a real attribute in order to make it accessible. You've presumably created coauthor as a virtual attribute using attr_accessor, but this doesn't automatically add it to the mass-assignment whitelist. To do that, also add it to your attr_accessible list.

How to use read_attribute when manually defining getter/setter (attr_accessor or attr_writers)

I set up a search model and want to require at least one field is filled out. I found a question that helps with the validation, Rails: how to require at least one field not to be blank. (I tried all answers, but Voyta's seems the best.)
The validation is working, except when I want to redefine the getter/setter via attr_accessor or attr_writer. (I have virtual attributes on the form that need to be apart of the validation.) To figure out what the problem is, I tested with an attribute that is a regular attribute item_length. If I add attr_accessor :item_length, the validation stops to work. So, I guess the question is how to I read an attribute's value without using dot notation. Since the validation uses strings, I can't use the normal way of reading.
Here is a snippet:
if %w(keywords
item_length
item_length_feet
item_length_inches).all?{|attr| read_attribute(attr).blank?}
errors.add(:base, "Please fill out at least one field")
end
Like I said, the virtual attrbutes (length_inches and length_feet) do not work at all, and the normal attribute (length) works except if I redefine the getter/setter.
You should consider read_attribute as a private method for reading Active Record columns. Otherwise you should always use readers directly.
self.read_attribute(:item_length) # does not work
self.item_length # ok
Since you are trying to call this dynamically, you can use generic ruby method public_send to call the specified method
self.public_send(:item_length) # the same as self.item_length
As stated in comment, use send
array.all? {|attr| send(attr).blank?}
For those wondering if send is ok in this case, yes it is: object calls its own instance methods.
But send is a sharp tool, so whenever you use with other objects, ensure you use their public api with public_send

Rails - Format number as currency format in the Getter

I am making a simple retail commerce solution, where there are prices in a few different models. These prices contribute to a total price. Imagine paying $0.30 more for selecting a topping for your yogurt.
When I set the price field to
t.decimal :price, precision:8, scale:2
The database stores 6.50 as 6.5. I know in the standard rails way, you call number_to_currency(price) to get the formatted value in the Views. I need to programmatically call the price field as well formatted string, i.e. $6.50 a few places that are not directly part of the View. Also, my needs are simple (no currency conversion etc), I prefer to have the price formatted universally in the model without repeated calling number_to_currency in views.
Is there a good way I can modify my getter for price such that it always returns two decimal place with a dollar sign, i.e. $6.50 when it's called?
Thanks in advance.
UPDATE
Thanks everyone.
I've elected to use Alex's approach because it seems very 'hackish' to do the includes just for formatting the number. Using his approach, I did:
def price_change=(val)
write_attribute :price_change, val.to_s.gsub(/[\$]/,'').to_d
end
def price_change
"$%.2f" % self[:price_change]
end
Cheers.
UPDATE 2
Caveat Emptor. Once you do this, you lose the ability to do operations to the number because it's now a string.
Please beware if anyone is facing the same problem as me.
Just add a method in your model which is named like your attribute in the database like:
def price
"$%.2f" % self[:price]
end
which gives you full control over the formatting or use the Rails provided helper method
def price
ActionController::Base.helpers.number_to_currency(self[:price])
end
this should do the trick.
hope it helps!
You can use the helpers module, but you should not include the whole module, because it includes a lot of methods which you may not really need or overrides some of yours. But you can use them directly:
ActionController::Base.helpers.number_to_currency(6.5)
#=> "$6.50"
You could also define a method for the helpers, so you can easily use them.
def helpers
ActionController::Base.helpers
end
"#{helpers.number_to_currency(6.5)}"
Have a look at this railscast
I'd suggest going with a Presenter approach, like Draper (see this reailscast) does.
Another solution would be to implement your own method in your model, i.e. formatted_price and do the formatting on your own, (i.e. with the ActionView::Helpers::NumberHelper module). But since models represent the plain data in your rails application, it's kinda shady doing something like this and it interferes with the convention over configuration approach, I think.
try
include ActionView::Helpers::NumberHelper
to your model

Resources