I've get a little problem.
My controller:
def new
#company = Company.new
#title = "Create company"
end
def create
#company = Company.new(params[:company])
#company.admin_id = current_user.id
if #company.save
flash[:success] = "Company created!"
redirect_to admin_path
else
#title = "New company"
render 'new'
end
end
new.html.erb
<%= debug params[:company] %>
<% form_for #company, :html => { :multipart => true } do |f| %>
<%= render 'shared/error_messages', :object => f.object %>
<%= render 'fields', :f => f %>
<div class="actions">
<%= f.submit "Submit company!" %>
</div>
<% end %>
Company.rb model
validates :name,
:presence => true,
:length => { :maximum => 20 }
validates_attachment_presence :logo
But after submitting form I've get anyway only one error:
Name can't be blank
Of course I'm filling name and logo fields.
Any ideas? Thanks.
You didn't include your _fields partial, and that's probably where your problem is.
Make sure your inputs have appropriate name attributes.
Try to instantiate your model in console and see if validations really work.
You can try something like this: c = Company.new; c.valid?; c.errors and you'll see your errors hash in console.
Related
My update function double the records for nested items in model on submit.
The one, which is NOT in the fields_for works as expecting, but every record in fields_for is doubling.
What am I missing? Any help will be highly appreciated
def edit
#printer = Printer.find(params[:id])
end
def update
#printer = Printer.find(params[:id])
if #printer.update_attributes(printer_params)
redirect_to #printer
else
render 'edit'
end
end
def printer_params
params.require(:printer).permit(:model, colors_attributes: [:color], materials_attributes: [:material], printer_photos_attributes: [:image_url] )
end
edit.html.erb
<%= form_for #printer, html: { multipart: true }, :url => url_for(:controller => 'printers', :action => 'update') do |p|%>
<%= p.text_field :model %>
<%= p.fields_for :colors do |color|%>
<%= color.text_field :color %>
<% end %>
<%= p.submit "Edit" %>
<% end %>
You are missing :id in printer_params. Without :id each your update for nested params is considered to be a new record. It should be as following for your colors_attributes:
def printer_params
params.require(:printer).permit(:model, colors_attributes: [:id, :color], materials_attributes: [:material], printer_photos_attributes: [:image_url] )
end
I guess, you should also correct your other nested attributes in this method.
I have most common in rails code
def new
#company = Company.new
#companies = Company.order(:name).pluck(:name, :id)
end
def create
#company = Company.find(params["company"]["id"]) rescue nil
unless #company
render action: 'new'
return
end
status = #company.update_attributes(total_licenses: params["company"]["total_licenses"].to_i, assigned_licenses: 0)
if status == true
redirect_to users_super_admin_index_path, flash: {notice: "License has been allocated to company."}
else
render action: 'new'
end
end
but when somthing wrong it should render action new, but it directly render template hence #company remains nil and throws an error
ActionView::Template::Error (First argument in form cannot contain nil or be empty)
I want to find the permanent and right solution, no hacks please :) . And the reason why i am facing this problem.
In my view -
<%= form_for #company, url: licenses_path, method: "post" do |f| %>
<%= f.label :id, 'Select Company' %><br/>
<%= f.select :id, #companies, :include_blank => "Select Company", required: true %><br/><br/>
<%= f.label :total_licenses, 'License' %><br/>
<%= f.text_field :total_licenses, required: true%><br/><br/>
<%= f.submit 'Assign'%>
<% end %>
Remember that render(action: ...) does not actually run the method in question, it just renders out the template. You will need to manually trigger the new method to do this.
I've got a pickem object that has one result. I'm having an issue getting the result to save properly to the database.
pickems_controller.rb
def results
#pickem = Pickem.find params[:id]
# #pickem.result = #pickem.build_result if #pickem.result.blank?
#pickem.result = Result.new
end
def update_results
#pickem = Pickem.find params[:id]
#pickem.result = Result.new params[:pickem][:result_attributes]
if #pickem.result.update_attributes params[:pickem][:result_attributes]
redirect_to edit_pickem_results_path(#pickem), :notice => 'The results have been successfully updated.'
else
render "edit"
end
end
results.html.erb
<%= simple_form_for #pickem, :url => edit_pickem_results_path(#pickem), :method => :put, do |f| %>
<%= f.simple_fields_for :result do |r| %>
<%= r.input :first_name %>
...
<% end %>
<%= f.submit :class => 'btn btn-success', :label => 'Submit Results' %>
<% end %>
pickem.rb
has_one :result, :dependent => :destroy
accepts_nested_attributes_for :result
result.rb
belongs_to :pickem
I was initially using the build_result code that is commented out in the controller but had to back out of that. With build_result a result record was saved to the database the instant somebody clicked into the results form. There are rules in place in the application that don't allow users to make any picks if a result has been entered. So even if a user clicked into the result form but didn't submit, the result was still being created.
How can I build my form and save the result record only when the user clicks save, and not when the form is loaded? The current solution I've pasted above does not work. It saves a result record with the appropriate foreign key but never gets the form data. If I dump #pickem.result the correct form data is in the result object, I just can't get it to save right. Other solutions I've tried save the form data correctly but have a foreign key of 0.
EDIT:
For whatever reason #pickem.result = Result.new was still saving a record to the database so I changed it to #result = Result.new and updated the form as follows:
<%= simple_form_for #result, :url => edit_pickem_results_path(#pickem), :method => :put, do |r| %>
<%= r.input :first_name %>
<%= r.submit :class => 'btn btn-success', :label => 'Submit Results' %>
<% end %>
Then using the suggestion from Chuck W of #result = #pickem.result.build params[:result], I get undefined methodbuild' for nil:NilClass`.
pickems_controller.rb
def results
#pickem = Pickem.find params[:id]
#pickem.result.blank? ? #result = Result.new : #result = #pickem.result
end
def update_results
#pickem = Pickem.find params[:id]
#result = #pickem.result.build params[:pickem][:result]
if #result.save
redirect_to edit_pickem_results_path(#pickem), :notice => 'The results have been successfully updated.'
else
render "edit"
end
end
Then, your view should look something like this:
<%= simple_form_for #pickem, :url => edit_pickem_results_path(#pickem), :method => :put, do |f| %>
<%= f.simple_fields_for #result do |r| %>
<%= r.input :first_name %>
...
<% end %>
<%= f.submit :class => 'btn btn-success', :label => 'Submit Results' %>
<% end %>
You might have to play around with how the parameters are being passed back to the update_results action (I'm pretty new to rails), but I think you get the gist of it.
A user has many user_levels and a user_level belongs to a user. Here is the code for user_level for update:
<%= simple_form_for #user do |f| %>
<% #user.user_levels.each do |level| %>
<%= f.fields_for :user_levels, level do |builder| %>
<p><%= render :partial => 'user_levels', :locals => {:f => builder, :i_id => level.position} %></p>
<% end %>
<% end %>
<% end %>
The code above will display the current user_level with selected set to the current position. The problem is that the update was not saved for user_level.
Here is the user_levels partial
<div class="fields">
<%= f.input :position, :collection => return_position, :prompt => "Choose position",
:label => false, :include_blank => true, :selected => i_id %>
<%= link_to_remove_fields "remove", f %>
</div>
Here is the string posted to the server for params[:user]. There are currently two positions for the user and one gets deleted as update:
{"name"=>"test eng", "login"=>"tester12", "password"=>"password", "password_confirmation"=>"password", "user_type"=>"employee", "user_levels_attributes"=>{"0"=>{"id"=>"5"}, "1"=>{"position"=>"elec_eng", "_destroy"=>"false", "id"=>"6"}}}
Any solution for child update? Thanks so much
UPDATE:
def new
#user = User.new
end
def create
#user = User.new(params[:user])
#user.input_by_id = session[:user_id]
if #user.save!
redirect_to URI.escape("/view_handler?index=0&msg=saved!")
else
flash.now[:error] = 'not saved!'
render 'new'
end
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
#user.input_by_id = session[:user_id]
if #user.update_attributes(params[:user])
redirect_to URI.escape("/view_handler?index=0&msg=saved}")
else
flash.now[:error] = 'not saved!'
render 'edit'
end
end
user.rb:
has_many :user_levels, :dependent => :destroy
accepts_nested_attributes_for :user_levels, :reject_if => lambda { |a| a[:position].blank? }, :allow_destroy => true
validates_associated :user_levels
Try removing the line #user.user_levels.each do |level| and please post what issue pops up then.
And does the user model accept nested attributes for user levels ?
Hey guys, this has been plaguing me all week long. I am new to Rails, so please be gentle :)
My root problem is I'm trying to write a form_for Post that will use autocompletion on an input to tie the post to a Client. The database is looking for a client_id, not a text name.
So I have tried a custom validation that will lookup the text value and replace it with an id.
My Post.rb file has this:
class Post < ActiveRecord::Base
belongs_to :client
attr_accessor :client_name
attr_accessible :client_name
before_validation_on_create :validate_client
def validate_client
self.client_id = 1 # just a test
end
def client_exists(passed_name)
return Client.where(:full_name => passed_name).first.blank?
end
end
But when I do this, none of the form variables get passed. The database gets all blank entries except for the client_id. How can I accomplish this? Why aren't my form variables being passed in? Many thanks in advance.
Edit 1: added create definition from posts_controller.rb
def create
#post = Post.new(params[:post])
respond_to do |format|
if #post.save
format.html {
redirect_to(posts_url) # redirect_to(#post, :notice => 'Post was successfully created.')
}
format.xml { render :xml => #post, :status => :created, :location => #post }
format.js
else
format.html { render :action => "new" }
format.xml { render :xml => #post.errors, :status => :unprocessable_entity }
end
end
end
Edit 2: Thanks to #apneadiving, I changed the attr_accesible to include the other attributes, and that passes the POST entries into the db.
attr_accessible :client_id, :time, :content, :client_name
But when I change the validate_client function to search for the client_id,
def validate_client
passed_name = self.client_name
if client_exists(passed_name)
c = Client.where(:full_name => passed_name).first
self.client_id = c.id
else
errors.add_to_base "Error"
end
end
It always gives me this error:
Called id for nil, which would
mistakenly be 4 -- if you really
wanted the id of nil, use object_id
Edit 3: Here's my post form. I can't get the value of :client_name properly.
<%= form_for(#post) do |f| %>
<%= render 'common/error_messages', :object => f.object %>
<div class="field">
<%= f.label :content %><br />
<%= f.text_area :content, :size => "50x6" %>
</div>
<div class="field">
<div class="sub-field">
<%= f.label :client_name %><br />
<%= f.text_field :client_name, :size => "26" %>
</div>
<div class="sub-field">
<%= f.label :date %><br />
<%= f.text_field(:time, :class => 'date', :size => "10", :value => Date.today.strftime('%m/%d/%Y')) %>
</div>
<div class="sub-field">
<%= f.label :time %><br />
<%= f.time_select :time %>
</div>
</div>
<div class="actions clear">
<%= f.submit %>
</div>
<% end %>
Edit 4: The solution. I was struggling to get the :client_name due to my text being too far tabbed in (I was originally privatizing the function and then took the word "private" out). A modified version of #apneadiving's answer solved it for me!
class Post < ActiveRecord::Base
belongs_to :client
attr_accessor :client_name
validate :validate_client
def validate_client
passed_name = self.client_name
unless client = Client.find_by_full_name(passed_name).blank?
self.client_id = Client.find_by_full_name(passed_name).id
else
errors.add(:client_name, "'#{passed_name}' cannot be found.")
end
end
end
Beware of your attr_acessible:
if you set one, you have to set all the variables that can be set through params. Otherwise they are protected against mass assignment
EDIT 1:
seems c.id is nil which means your client_exists function doesn't work as expected. Try the following (not tested):
def validate_client
unless client = Client.find_by_full_name(client_name).nil?
client_id = client.id
else
errors.add_to_base "Error"
end
end
Your client_exists code is wrong, it returns true if it doesn't exist.
Also, since your client_exists and the validation reuse the same query i would rewrite that a bit.
def validate_client
passed_name = self.client_name
existing_client = Client.where(:full_name => passed_name).first
if existing_client
self.client_id = existing_client.id
else
errors.add_to_base "Error"
end
end