Ruby On Rails : I need some explanations about form - ruby-on-rails

I am creating a RoR application. So i want to create a web form with select drop down type. I found the following code in a project. Here is a form:
<div class="field">
<%= f.label :key_words %><br>
<%= f.collection_select(:skill_list, User::all_tags, :name, :name, {},{multiple: true}) %>
</div>
I create in User controller class :
class UsersController < ApplicationController
...
def all_tags
#tags = Tag.all
end
end
Here is database :
1. I don't understand what is User::all_tags ? Ok understood
2. I cannot see tags in my select drop down. What is missing ?

You need to understand the context first, and then need to understand it.
You are passing: User::all_tags, :name, :name
User::all_tags returns you most probably an array/hash, and this array will be utilized to populate collection_select, but a general option tag has two things: 1) value that will exactly be sent to the server, and a piece of text that will be shown, but won't necessarily be sent to the server.
The first argument after User::all_tags determines what to have for value, and second argument decides what to have for that apparent text.
<option value="First argument goes here ">"Second argument">/option> # this isn't valid code

It seems to me all_tags a method that placed in user class and have an array or hash containing the values
you can call that method like User.all_tags as well

Related

I want to return a single result using .find() with Ruby on Rails

I have a user view and a rental view.
In my rental view im trying to show the current users name. I think I am pretty close but I can't work out this last bit.
This returns all of my users in a select list
<%= f.select :user_id, User.find(:all).collect {|t|
[t.user_name, t.id]} %>
This returns my current users ID
<%= f.number_field :user_id %>
So I thought I could do something like
<%= f.select :user_id, User.find(:user_id).collect {|t|
[t.user_name, t.id]} %>
Which I would want to only return the current user in a select list with their id as the value and their name in the list. If I do the above it tells me
Couldn't find User with id=user_id
So user_id is being passed as a literal string but I want to pass the user_id variable which should be somthing like 10. I don't know how to pass the user_id as a variable.
I'm fairly new to ROR, I might be going about this the completely wrong way. Any help is much appreciated.
I am assuming you have a rental object, for which you show the form, I assume it is an instance variable #rental, furthermore I assume that inside your Rental class there is the following relation
class Rental
belongs_to :user
end
Then you could just write the following:
f.select :user_id, [[#rental.user.user_name, #rental.user.id]]
Hope this helps.
On a related but less important note: it is really weird to have a column called user_name for a user: I would call that column just name, since it is part of a user anyway.
find() wants a variable, not a symbol. And :all probably isn't what you want. You should write a method in your controller like:
def user(u)
#user = User.find(u)
end
Then call the method in the view or whatever like (I don't know exactly what you're trying to do here):
<% user(current_user.id) %>
Then you'll have a #user object with which you may play, i.e.:
<%= f.select :user_id, [[#user.name, #user.id]] %>
I think you should be able to do:
<%= f.select :user_id, User.find(f.object.user_id).collect {|t| [t.user_name, t.id]} %>
This does seem a little odd to me though. I'd have thought either:
Your object has a proper association to the relevant user, in which case you should be able to do f.object.user.user_name and f.object.user.id.
If you genuinely want the currently logged in user, you should probably be asking your authentication framework/code for the reference. E.g. if you were using Devise, it would be current_user.
As an aside, I don't really understand why you want a select list just containing the current user - is that definitely what you're trying to achieve, or have I misunderstood?

What's the best way to do form field validations for phone numbers in Rails view without using a model?

I have the following form field in my index.html.erb view:
<%= form_tag("/calls/call", :method => "post") do %>
<br />
<%= text_field_tag(:call_to, "Number to call") %>
<br />
<%= text_field_tag(:call_from, "Number to call from") %>
<br />
<%= submit_tag("Dial") %></a>
<br />
<% end %>
I want to constrain the field to allow only 10 digit US phone numbers without using a model validation (as there is no model).
There's probably a lot of ways to do this, but what do you folks find to be the simplest to implement?
I've tried using the 'active_attr' gem, but didn't have much luck. With 'active_attr' I created a model called Call. Here's what the model looks like:
class Call
include ActiveAttr::Model
attribute :call_to
attribute :call_from
# attr_accessible :call_to, :call_from
validates_presence_of :call_to
validates_presence_of :call_from
end
My controller looks like this:
class CallsController < ApplicationController
def call
call_to = params["call_to"]
call_from = params["call_from"]
call_to.to_i
call_from.to_i
puts call_to
puts call_from
end
end
Am I supposed to instantiate an instance of a Call class in the controller or something along those lines?
#call = Call.new
Thanks in advance!
One client side option would be using the HTML5 type=tel input. Here's a link to some documentation. You will still want some server side validation though.

Rails - Add a method to a textfield

I'm trying to get the checkSwear method to run on each textfield before it's submitted..
I have basically this: (stripped down)
<%= form_for(#profile) do |f| %>
<div class="field">
<%= f.label 'I love to ' %>
<%= f.text_field :loveTo %>
</div>
<div class="field">
<%= f.label 'I hate to ' %>
<%= f.text_field :hateTo %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
In my controller I have:
def checkSwear
antiSwear.checkSwear(What goes here?)
end
In routes:
match '/check' => 'profiles#checkSwear'
Any help much appreciated!
(checkSwear is a separate gem; i.e. a separate problem! The what does here means what kind of variable is received from the form, to be put through the checkswear gem)
UPDATE:
Sorry for the camelcasing, I'm a Java developer studying Rails etc., old habits die hard. This is for a project. I'm supposed to be writing a small gem to do some ruby logic and apply it to something. The contents of the gem are:
module antiSwear
#swearwords = ["f**k", "f***ing", "shit", "shitting", "lecturer"]
#replacements = ["fornicate", "copulating", "poop", "pooping", "Jonathan"]
def self.checkText(text)
#swearwords.each do |swearword|
if text.include?(swearword)
index = #swearwords.index(swearword)
replacement = #replacements[index]
text.gsub(swearword, replacement)
end
end
return text
end
end
:/
This should really be done in model validations.
class Profile < ActiveRecord::Base
validate :deny_swearing
private
def deny_swearing
if AntiSwear.check_swear(love_to) || AntiSwear.check_swear(hate_to)
errors.add_to_base('Swearing is not allowed.')
end
end
end
That said, if you insist on this being in controller, you can check params[:profile][:love_to] and params[:profile][:hate_to] to see what's been submitted.
P.S. In this example I used proper ruby naming conventions, since we don't use "camelCasing".
Are you doing this as part of validation? You can do it one of a few ways. You can run the check before save, via a custom validation method or override the setter directly. I show you the custom validation approach here:
class Profile < ActiveRecord::Base
validate :clean_loveTo
protected
def clean_loveTo
errors.add(:loveTo, "can't contain swears") if antiSwear.checkSwear(loveTo)
end
end
I'm assuming checkSwear returns a boolean here.
I'd use an intersection on arrays, one of which is the source text split into words, then gsub the replacements in. You have to be sure to have a 1:1 relationship between the words and their replacements, in which case I'd suggest using a hash for your dictionary (coincidentally what hashes are sometimes called in other languages).
module antiSwear
# var names changed for formatting
#swears = ["f**k", "f***ing", "shit", "shitting", "lecturer"]
#cleans = ["fornicate", "copulating", "poop", "pooping", "Jonathan"]
def self.checkText(text)
# array intersection. "which elements do they have in common?"
bad = #swears & text.split # text.split = Array
# replace swear[n] with clean[n]
bad.each { |badword| text.gsub(/#{badword}/,#cleans[#swears.index(badword)] }
end
end
You might need to futz with text.split arguments if the replacement gets hung up on \n & \r stuff.

Rails - default value in text_field but only for new_record?

On a Content model have an attribute named slug. When creating a new record, I want to use a helper to populate this field, but on an existing record I want to use the value from the database.
Currently I have:
<% if #content.new_record? %>
<%= f.text_field :slug, :value => "#{generate_slug(6)}" %>
<% else %>
<%= f.text_field :slug %>
<% end %>
But that seems a bit verbose. Is this the best way, or is there no other way? (Rails newb just trying to find the "Rails way" on issues I'm unsure of)
Edit
I should note that the helper is currently in /app/helpers/application_helper.rb Moved to be a private action in the Contents controller. David's answer worked great.
In your controller
#content.slug ||= generate_slug(6)
This will assign a value to the slug attribute if none is present
Then, in your view you can simply use
<%= f.text_field :slug %>
Options
Try after_initialize callback in your model.
Try creating a method in your model where you set defaults and call it in your new action in the controller. Also call this method if your create fails and you render new. Remember to set default only when no value exists by using the ||= operator.
Example to follow. I'm typing on phone!
I happen to use jQuery in my projects, so when I want some functionality like this, I usually use something like labelify. Then, I'd use something like <%= f.text_field :slug, :title => generate_slug(6) %>. (Hot tip, you don't need to put the #generate_slug call inside of a string if it returns something that will resolve to a string by itself, in fact it's more performant if you don't.)
If you don't want to go with jQuery approach, you might want to wrap this piece of logic in your model.
def Content < ActiveRecord::Base
def slug
self.new_record? ? self.slug_for_new_record : attributes[:slug]
end
private
def slug_for_new_record
# I don't know what you're doing in generate_slug, but it sounds model-
# related, so if so, put it here and not in a helper
end
end
If it really belongs in the view, still another option is to just make your Ruby a little bit more concise (you'll have to judge if this is more readable):
<%= f.text_field :slug, :value => (generate_slug(6) if #content.new_record?) %>
Don't forget the parens surrounding (generate_slug(6) if #content.new_record?). If you do, the if will be applied to the text_field, which is not what you want.
But there are still more ways to do it. The above line of code isn't great if your logic might change and you're pasting this code all over your rails project. When I wanted to add a 'required' class to my text fields but only if they were a new record (we had some legacy data that we didn't want to make people clean up), I created my own form builder with a required_field method that just called text_field and added a 'required' class if the item was a new record. This might seem like a work, but we have around 20 different forms, each with potentially multiple required fields, and it's a lot easier to change the business logic in one place. So if you really think this logic belongs in the view but you've got a ton of these lines of code and you don't want to have to change it in a million places, then FormBuilder is the way to go. I think this is in most cases prettier and more appropriate than a helper, but again, beauty is in the eye of the beholder. Here's my code somewhat adapted for your case:
# config/environment.rb
ActionView::Base.default_form_builder = NamespacesAreFun::FormBuilder
# lib/namespaces_are_fun/form_builder.rb
module NamespacesAreFun
class FormBuilder < ActionView::Helpers::FormBuilder
def slug_field(method, options = {})
opts = options.to_options
opts.merge!(:value => generate_slug) if self.object.new_record?
text_field(method, opts)
end
end
end
# views/.../your_view.html.erb
<%= f.slug_field :slug %>
Hopefully in all of these different approaches is one that fits your project.

how to use an array in form_for?

I've got a user model which contains a field called, lets say, text1. In the users/new form I want to have 4 individual text boxes for this text1. In my model I will take values from these boxes and concatenate them together as comma separated values and store them in the DB. To give you an understanding, this is what I want.
<input type="text" name="user[text1][]" />
<input type="text" name="user[text1][]" />
<input type="text" name="user[text1][]" />
<input type="text" name="user[text1][]" />
How do I get this using form_for helper method? For now please don't worry yourself about the accessor method in the model, that is all taken care of. Thanks a ton.
Add few virtual attributes to your User model
class User < ActiveRecord::Base
attr_accessor :text1_part1
attr_accessor :text1_part2
attr_accessor :text1_part3
attr_accessor :text1_part4
def before_validation
self.text1 = "#{self.text1_part1}#{self.text1_part2}#{self.text1_part3}#{self.text1_part4}"
end
# make sure you fill the correct values for
# the text parts for an existing record.
# This can be done by implementing `after_find` or overriding
# `text1=`.
end
In your view code use the new attributes instead of text1
<% form_for(:user) do |f| %>
#some code
<%= f.text_field :text1_part1>
<%= f.text_field :text1_part2>
<%= f.text_field :text1_part3>
<%= f.text_field :text1_part4>
#some code
<%= f.submit "Save">
<% end %>
The previous answer gives a solution, so I am just providing some background as to why what you are asking for does not work they way you might hope.
You can indeed create a form with multiple input fields of the same name, and that data will be posted. However, when rails receives the post it automatically parameterizes the post data and/or url parameters. It essentially splits on the & and assigns the key/value pairs to the params hash. The outcome of this is that params[:user][:text1] (from your example) will have the value of the last instance of the user[text1] it encountered, since it is simply a value assignment to an existing key. You might want to dig into ActiveRecord multiparameter assignments to get an idea of how datetime attributes work, since they are similar to your use-case.
I am working on something similar and it sounds like maybe serialization is what you are looking for. Unfortunately I don't have my issues solved yet, so I can't provide anything more concrete.

Resources