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.
Related
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
I've got a Rails 4 app with a service that loads required objects on a new/edit document action, and this is a method from it:
def template_variables
if #document.template_variables.any?
TemplateVariable.where(id: document_vars).each do |v|
next unless User.method_defined?(v.name.to_sym)
v.update_attribute(:text, #user.send(v.name.to_sym)) # problem line, persists the change when i don't want to
v.text = #user.send(v.name.to_sym) # also a problem, doesn't update the value in the form at all
end
else
TemplateVariable.where(id: master_vars)
end
end
I need a solution for the two problem lines (they are just two things I've thought of, and they aren't supposed to both be there but I've included both for the sake of my problem).
The first updates and persists the change to the model which is behaviour I don't want. The second line doesn't do anything, where logically it seems like it should replace whatever text was in that variable in the form with #user.send(v.name.to_sym). It appears to do nothing.
Is there are solution to this problem that I'm unaware of?
Bonus points if there's a way to list the fields with new values to display in a flash[:notice].
Update now with relevant form code.
<%= v.input :text, as: :string, input_html: { value: v.object.text } %>
Setting the value/vs not setting it doesn't change anything either.
If you've got an instance variable that you're passing from your controller, you can set (but not save) values on that variable which will be available in the view.
For example, you can set the first and last name of a new user by passing in arguments or setting the attributes in the controller:
#UsersController
def new
#user = User.new(first_name: 'John')
#user.last_name = 'Smith'
end
In the view
#users/new.erb.html
<%= #user.first_name # will be John %>
<%= #user.last_name # will be Smith %>
But in your case, you're using update_attribute, which saves the record changes. Instead, you should be creating an instance variable, setting (but not saving) the values on that, and using that in the view/form
e.g.
#varibales = TemplateVariable.where(id: document_vars)
#variables.each do |variable|
#change what you want here
variable.foo = 'bar'
end
And then reference your #variables object in the view/form.
In saying all of that, you should strive to only use one instance variable in your controller, consider using form objects, if you need to pass multiple values from the controller to the view.
As for the flash notice, you can display whatever you like as a flash notice by setting that in the controller, assuming you've got your view setup to display flash notices as shown here
flash[:notice] = "The value of #{#variables.first.foo}"
I have a simple model called Discussion which has a boolean column called resolved.
In my form, I have the following code
<%= form_for(#discussion) do |d| %>
...
<%= d.check_box :resolved %>
<% end %>
And in my controller, I have the following:
def update
#discussion = Discussion.find(params[:id])
if #discussion.update_attributes(params[:discussion])
etc...
end
end
When I submit the form, I can see that the parameters are being sent to the server...
Parameters: {"utf8"=>"✓", "authenticity_token"=>"AsGsRHwiVva/+kTrBs0IjLeZwj1ZmXBuKZr9Pg/N6Xk=", "discussion"=>{"shortdesc"=>"Talk about something.", "content"=>"Try to update check box.", "resolved"=>"1"}, "commit"=>"Update Discussion", "id"=>"1"}
But the query doesn't include anything about updating that field.
AREL (14.9ms) UPDATE "discussions" SET "content" = 'Try to update check box.', "updated_at" = '2011-07-18 17:53:50.783176' WHERE "discussions"."id" = 1
Any idea on what I'm missing?
There are 4 reasons why this could be happening:
resolved is already set to true in the database.
You defined the resolved= method in your model and it no longer sets the attribute.
You have attr_protected :resolved.
You have attr_accessible but do not have :resolved in the list.
does your boolean column have a default? If it defaults to true - rails might not bother adding it to the set of attributes.
Alternatively, have you got attr_protected set for that column? if so - rails will never add that field to the attributes using update_attributes. You'll need to do that manually.
All,
I had recently begun rails and was taking over someone else's code and found another scenario that was not covered here that was getting me.
When using the style pointed to by this link, the params are formed in a separate method. I had to update the "_params" method to add it to the allowable list.
http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html
Are you sure that the element is sended it?
I mean, form element without checked the element are not sended, so you have to put an hidden checkbox for default false.
Problem solved. HTML5 localStorage messed with me.
I'm trying to populate a form with parameters from the new()-method, and I can't get it to work.
Every user has default values for the form saved in the database(in a table called defaults), and when you create a new record I want it to be populated with the values from that table.
#default = Default.find_by_user_id(current_user.id)
#invoice = Invoice.new(:title => #default.title, :company_information => #default.company_information)
render 'create'
and then in my view:
form_for #invoice, :url => { :action => "create"} do |f| ...
What happens is that the values that are default for invoice are created, but not the ones created in the new()-method.
The weirdest part is that when I check the source code after the page is loaded, the inputs value attributes is filled with the correct information, but not rendered on the page...
What you're doing here:
Invoice.new(:title => #default.title, :company_information => #default.company_information)
Makes sense and should work…unless those fields are protected from mass assignment.
class Invoice << ActiveRecord::Base
attr_accessible :some, :other, :fields
...
end
This would allow you to set :some, :other, (and) :fields when you initialize your Invoice object, but it will prevent you from setting any other "attributes".
Strange, I don't see anything wrong with what you are trying to do... maybe something on the browser side (javascript, css, etc) is fowling things up?
Check to see if there is something selectable inside the form inputs or try creating a vanilla form without any javascript or css. Or, you might even try simply printing the contents of the attribute in the html (without using input/textarea tags) using something like:
<%= #invoice.title %>
This will at least help confirm that the default values where indeed set. Additionally, using:
<%= f.object.title %> # place me inside the form_for block
will help you confirm that the form builder instance also has the correct value.
Good luck.
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)