Using an instance variable as the value of a hidden_field? RoR - ruby-on-rails

im in the process of creating a form that then creates a user and sends out a generated password in an email. I'm using devise, for reference. The password must be "random" as directed, so SecureRandom.base58(8) is how I will be generating the password.
My thought process so far is to generate the variable inside the create action of the users controller, like so - #generated_pass = SecureRandom.base58(8)
and then call that variable inside the view.
The field I'm unable to get working is:
<%= f.hidden_field :password, class: 'form-control', value: #generated_pass %>
The form works when I enter an acceptable string (1 number, 1 capital at least) as the value: so I know it's not the form breaking, the problem I get when submitting with this variable is a rollback with no other information.
Have I declared the variable wrong? Should I create a method and then somehow call that method as the value? Additionally, I've tried -
<%= f.hidden_field :password, class: 'form-control', value: SecureRandom.base58(8) %> to no avail.
Any advice would be welcome, thankyou.
Rails -v 5.0.7.2 | Ruby -v 2.6.4

Why don't you use before_save or before_validation callbacks on you model ?
This type of data should not be modified or altered in the view or controller.
Something like this in your User model:
before_validation :do_before_validation
def do_before_validation
self.password = SecureRandom.base58(8) unless self.password.present?
end

Related

simple_form_for: Removing root model name from params

When I create a form using simple_form_for #model, upon submit the post params has all the attributes grouped under params[model]. How do I get simple_form to drop this grouping and instead send it directly (under params root)?
<%= simple_form_for #user, do |f| %>
<%= f.input :name %>
<%= f.input :password %>
<%= f.submit %>
Now the name and password attributes would normally be sent under params[:user][:name], params[:user][:password] etc. How do I get simple_form to post these as params[:name], params[:password] etc.?
Thanks!
Ramkumar
ps: In case you are wondering why I need this, the bulk of my app is to serve as an API and I have built a set of methods to validate a request which expect some attributes to be in root. In a rare instance (forgot password), I actually need to present a form and I am looking for a way to use these methods.
you can explicitly define the name for an input by passing input_html to it:
input_html: { name: :name }
(needed this myself for sending an resource to a thirdparty endpoint with redirect to my side which relied on the plain attribute names, but i actually wanted not to built up label and input via the tags ;) )
also see simple form builder impl
Two ways I can think of:
The first is, don't use simple_form to build your form, but do it by hand or with the form_tag and *_tag methods. These will allow you to more closely specify what parameters are used in your form.
If you want to keep simple_form, though, then have it call a different controller action. Refactor the controllers to strip out the logic into a separate method. Something like:
class UsersController
def create_from_api
controller_logic(params)
end
def create_from_form
controller_logic(params[:user])
end
def controller_logic(params)
[actual work happens here]
end
end

Rails 3 virtual attributes not saving

I have a model with virtual attributes:
attr_accessible :published_at
def published_at_text
I18n.localize(published_at, format: :long_no_day_with_seconds) if published_at
end
def published_at_text=(text)
self.published_at = Chronic.parse(text)
end
This works fine in the unit tests, but does not save when the published_at_text field is changed in the view. I've tried using attr_accessible :published_at_text, and adding published_at_will_change! to the setter method, but I can't get this to work.
The development.log shows that the changed value of published_at_text is being passed in, but adding a call to Rails.logger in the setter seems to indicate that it's not even getting called.
What am I missing here?
Well, you do not provided your controller method that created your object using the params hash, but I can make a guess.
You should call explicity the setter with the parameter passed to the controller.
Then checks if the value gets updated on your model.
Found it: the fields for the virtual attribute weren't being passed back as part of the article, so they weren't being shown in the params hash.
Replacing this:
<%= text_field_tag 'article_published_at_text', #article.published_at_text, class: 'text_date show_seconds' %>
with this:
<%= text_field_tag 'article_published_at_text', #article.published_at_text, name: 'article[published_at_text]', class: 'text_date show_seconds' %>
fixed the problem.

Undefined methods using strings to populate inputs in Rails

I'm trying to pass a string from a variable in my Rails app to the database. It's the user's email address. I cannot for the life of me figure out why I'm getting an "undefined method `merge'" error.
Here's the offending code:
<%= f.email_field :commenter, current_user.email %>
Any help will surely help. Cheers!
Rails expect the second argument to be a hash, so you'd want to do
<%= f.email_field :commenter, value: current_user.email %>
Or better yet, set the :commenter attribute in that particular model in the controller (after you initalize/build it), then you can leave out this value hax. That way, when use edit this, post the form, and get a validation error, the value will be what's user were posting, not current_user.email.

Rails 3 / Form without Model: How do I create a form that is not tied to a model?

I have a model, and I have a view that displays a form for creating a new object based on that model. Let's call that form, Form1.
Once the user submits Form1, the object is created. I then want to display, on the following page, a second form Form2, which asks the user to check off various options before the object is saved to the database.
My problem is probably extremely basic. I don't know how to create Form2, given that it is not tied directly to the model. Because I am a Rails newbie, I have only created forms as following:
form_for(#object) { |f| ... }
#object is an object instantiated from the model
Problem: I do not believe that kind of code will work for my purposes here. How do I create Form2, given that it must not be based on #object or #object's model?
Some specifics from my app:
The site accepts values (Form1) before redirecting to an OAuth server.
When the user verifies her credentials on the OAuth server, she is redirected back to my site. An XML-RPC request then retrieves information about the user's account on the OAuth server.
The XML response may indicate that the user has only one account on the OAuth server. If so, some values are retrieved from the XML and added to the object--which is then (finally) saved in the database--and the user is redirected to a success page.
However, if the XML response indicates that the user has multiple accounts on the OAuth server, I want to display a form (Form2) that allows the user to select which accounts on the OAuth server to associate with my site. So Form2 really asks the user how many objects to create, rather than about specific attributes of an object.
Use form_tag instead of form_for, then use the appropriate form helpers: text_field_tag instead of f.text_field, text_area_tag instead of f.text_area, etc. Example:
<%= form_tag "/my_controller/update2" do %>
<%= text_field_tag "account", "default info" %>
<%= submit_tag "Save" %>
<% end %>
The Rails API site has a great reference to all of the _tag helpers: http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html
Starting in rails3, validations have been decoupled from ActiveRecord so you can create vanilla objects that can be used as validators with the form helpers:
class Person
include ActiveModel::Validations
attr_accessor :first_name, :last_name
validates_each :first_name, :last_name do |record, attr, value|
record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
end
end
and then in your template:
<%= form_for(Person.new) do |f| %>
...
It's a handy way to get the benefits of the form helpers for things like email forms without having to create a model object tied to your schema.
To create a table-less model,
class Person
include ActiveModel::Model
attr_accessor :first_name, :last_name
validates :first_name, :last_name, presence: true
end
Then in your view,
<%= form_for(Person.new) do |f| %>
.... your form ....
<% end %>
Another similar solution can be found at RailsCasts:
Active-Model
If you are looking to use SimpleForm then there is a specific answer for that here Does form_tag work with Simple_form?

wrong number of arguments (2 for 1) - Rails

I am really really stuck and annoyed with this right now.
I am running Rails 2.3.5
My View/pages/customers.html.erb simply has:
<% form_tag do %>
First Name
<%= text_field_tag :firstName, params[:firstName] %>
Last Name
<%= text_field_tag :lastName, params[:lastName] %>
<%= submit_tag "Enter" %>
<%end%>
My Models/customer.rb simply has:
class Customer < ActiveRecord::Base
attr_accessible :firstName, :lastName
end
My Controller/pages_controller has
class PagesController < ApplicationController
def custs
#cust = Customer.new(params[:firstName], params[:lastName])
#cust.save
end
end
so as you see I am just trying to enter two fields from front end and then save them to the DB. However, whenever i load my page it give me error:
wrong number of arguments (2 for 1)
pages_controller.rb:3:in new'
pages_controller.rb:3:incusts'
weird thing is that when I use the sandbox script/console I am able to insert data fine.
What is going on here? please someone explain!
http://apidock.com/rails/ActiveRecord/Base/new/class here is a little explanation of the new function. The crucial part - "pass a hash with key names matching the associated table column name". Instead of #cust = Customer.new(params[:firstName], params[:lastName]) you should have #cust = Customer.new(:firstName => params[:firstName], :lastName => params[:lastName]). This should do the trick.
The quick fix is to change line 3 of pages_controller to this:
#cust = Customer.new({:firstName => params[:firstName], :lastName => params[:lastName]})
Without proper keys Rails has no idea what values you are passing and in what order.
The bigger problem seems to be that your form is not setup properly. You might have a great reason for it, but if not, I would recommend creating a blank Rails project, and using generate scaffold to see how a normal Rails form/controller is setup.
Since new takes a hash, from which attributes will be set where the hash has the corresponding keys, Customer.new(params) should be sufficient, shouldn't it? Unless params also has keys for attributes that you don't want to be set in this case, I suppose.
Obviously your sample code may have been edited-down to better present the problem, but as shown, the #new/#save pair can usually be condensed down to Customer#create(params)

Resources