How to save data in rails with no form? - ruby-on-rails

I am new to rails and I am just learning the basics.
This is my code on saving data:
app/controllers/employee_controller.rb
class EmployeesController < ApplicationController
def index
render json: #employees = Employee.all
end
def show
render json: #employee = Employee.find(params[:id])
end
def new
#employee = Employee.new
end
def create
#employee = Employee.new(employee_params)
#employee.save
redirect_to #employee
end
private
def employee_params
params.require(:employee).permit(:fname, :mname, :lname, :contactno, :address, :username, :password)
end
end
app/views/employees/new.html.erb
<%= form_for #employee do |f| %>
<p>
<label>First Name</label><br>
<%= f.text_field :fname %>
</p>
<p>
<label>Middle Name</label><br>
<%= f.text_field :mname %>
</p>
<p>
<label>Last Name</label><br>
<%= f.text_field :lname %>
</p>
<p>
<label>Contact No.</label><br>
<%= f.text_field :contactno %>
</p>
<p>
<label>Address</label><br>
<%= f.text_area :address %>
</p>
<br>
<p>
<label>Username</label><br>
<%= f.text_field :username %>
</p>
<p>
<label>Password</label><br>
<%= f.text_field :password %>
</p>
<br>
<p>
<%= f.submit %>
</p>
But, my goal is to save right away without the html form. (NO INPUT) Like when I visit a certain URL and the values are automatically saved in the database.
For a start, I would like to assign a constant value in every field just to see how it works.
Example,
fname='sample name'
mname='sampleMidName'
lname='sampleLastName'
and etc...
How can I assign those values right away after a certain URL/site is visited.

You start by adding a method to your controller
def update_fname
# get the parameters
fname = params[:fname]
# get the employee ID
id = params[:id]
# find the employee
#employee = Employee.find(id)
# update the employee
employee.update_attributes(fname: fname)
redirect_to #employee
end
Then, in your route, you add:
resources :employees do
get 'update_fname'
end
And you call the route, who should be http://localhost:3000/employees/{:id}/update_fname?fname={your_fname}

In your controller try something like:
class EmployeesController < ApplicationController
def custom
#employee = Employee.create(fname: "sample name")
end
end
and define proper route in config/routes.rb:
get "/custom" => "employees#custom"
When you enter proper url in your browser, like:
localhost:3000/custom
The Employee should be saved.
Good luck!

Related

Rails 5 - Render New with Parameter

I have checked old similar post but but I'm still having problems.
When I create a new listing the URL looks as below:
http://localhost:3000/listings/new?plan=1
In the form_for I'm hiding some fields when plan=1
<%= form_for(#listing) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.hidden_field :plan, :value => #plan %>
<%= f.label :Title %>
<%= f.text_field :title, class: 'form-control' %>
<!-- don't show description for standard plan -->
<% if #plan != 1.to_s %>
<%= f.label :Description %>
<%= f.text_area :description, :rows => 10,
placeholder: "Describe your business...", class: 'form-control' %>
<% end %>
In the ListingsController I set the plan in before action:
before_action :set_plan, only: [:new, :create]
def set_plan
#plan = params[:plan]
end
so I can use it as hidden field on the form above.
My problem starts when I save the form with errors.
The new form URL changes to http://localhost:3000/listings.
I can see the #plan=1 still on the form:
<input value="1" type="hidden" name="listing[plan]" id="listing_plan" />
, but now the form is showing all fields (which should be hidden due to this condition <% if #plan != 1.to_s %>)
Actions in ListingsController:
def new
#listing = Listing.new
end
def create
#listing = current_user.listings.build(listing_params) if logged_in?
#plan = #listing.plan
if #listing.save
flash[:success] = "Listing created!"
redirect_to #listing
else
render 'new'
end
end
I have tried something like that but no success:
render :action => 'new', :plan => #listing.plan
and few other things
How can I hide those fields on error?
You should be able to solve this by modifying your ListingsController to set the plan on create. Specifically, in ListingsController.rb:
# app/controllers/listings_controller.rb
before_action :set_plan, only: [:new, :create]
Also, be sure your listing_params method permits :plan.
If you want this to function on update, then add :update to your before_action as well.
I have it fixed.
#plan = params[:plan]
was returning string (when the field in DB is integer), so I changed it to:
#plan = params[:plan].to_i
and now in the form I have the below for all actions:
<% if #plan != 1 %>

Wrong number of arguments error (0 for 1) in Ruby on Rails 4 when creating a form for user submission

at the moment I am attempting to create a form for my website that will allow for users to input information and then the information with be POST'ed to my database for storage. I am a new ruby on rails developer so keep that in mind.
I was able to get to the point where the user could see the form and type in information but once they hit the submit button I recieve an error, and that error is
ArgumentError in StudentsController#create
wrong number of arguments (0 for 1) in app/controllers/students_controller.rb:13:in `create'
The parameters that were sent were the following
{"utf8"=>"✓",
"authenticity_token"=>"bLalQ9Ek5ziaGiGHj03AGPCTIABAgcT+o4eTgN44qv44dxNDlrGA0h2u5BSTQVTMh+YgA/mLPQee05lT7mxCsw==",
"student"=>{"first_name"=>"Andrew",
"last_name"=>"Terra"},
"commit"=>"Submit"}
Below is my students_controller.rb file.
class StudentsController < ApplicationController
def index
#students = Student.all
end
def new
#student = Student.new
end
def create
#student = Student.new(params.require[:student])
if #student.save
redirect_to students_path
end
end
def destroy
#student = Student.find_by_id(params[:id])
if #student.destroy
redirect_to students_path
end
end
end
Below is my views/students/_form.html.erb file
<%= form_for #student do |f| %>
<p>
<%= f.label :first_name %>
<%= f.text_field :first_name %>
</p>
<p>
<%= f.label :last_name %>
<%= f.text_field :last_name %>
</p>
<%= f.submit "Submit" %>
<% end %>
Below is my /views/students/index.html.erb file
<%= link_to "Create new information", new_student_path %> <br /> <hr>
<% #students.each do |fo| %>
Firstname: <%= fo.first_name %> <br />
Lastname: <%= fo.last_name %> <br />
<%= link_to "Delete info?", student_path(student), :data=>{:confirm=>"Are you sure ?"}, :method=> :delete %>
<br />
<hr>
<% end %>
Finally, here is my /views/students/new.html.erb file
Enter new info
<hr>
<%= render :partial => "form" %>
And I did remember to put resources :students in my routes file. I searched around and found other people who had previously had this problem but none of the solutions worked on the code that I have written. So I was wondering if anyone could point me in the direction of where the bug is and how exactly I can fix it. Thank you.
You need to add a new private method:
private
def student_params
params.require(:student).permit(:first_name, :last_name)
end
And then as said before change your create method to:
def create
#student = Student.new(student_params)
if #student.save
redirect_to students_path
end
end
I recommend reading the documentation on Strong Parameters - to better understand how they work. https://github.com/rails/strong_parameters
You have to change
params.require[:students] to params.require(:students)
But this is still not good way to handle your params for create action, you should add private method student_params to your controller where you would whitelist your params. Like this:
def student_params
params.require(:student).permit(:first_name, :last_name)
end
Here you can find more about it,
http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html

Rails 4, how to update a model field from a different controller?

I am trying to update an invoice fields, when checking out in the carts controller. These must be present when checking out, or it should fail. However, I can't get it to update, much less validate them.
Here is my code:
cart show view:
<div class = "row">
<div class = "col-lg-3 col-lg-offset-6 text-left">
<strong>Customer: </strong>
<%= collection_select(:invoice, :customer_id, #customers, :id, :full_name, {:prompt => 'Please Select'}, class: 'form-control') %>
</div>
<div class = "col-lg-3 ext-left">
<strong>Seller: </strong>
<%= collection_select(:invoice, :employee_id, #employees, :id, :full_name, {:prompt => 'Please Select'}, class: 'form-control') %>
</div>
<div class = "col-lg-12 text-right">
<%= form_tag carts_checkout_path, method: :post do |f| %>
<%= submit_tag 'Complete', class: 'btn btn-success' %>
<% end %>
</div>
</div>
carts controller:
class CartsController < ApplicationController
def show
#invoice = current_invoice
#invoice_products = current_invoice.invoice_products
#customers = Customer.all
#employees = Employee.all
end
def checkout
current_invoice.customer_id = params[:customer_id]
current_invoice.employee_id = params[:employee_id]
current_invoice.save
redirect_to current_invoice
end
end
current_invoice is the current session's invoice, related to the cart. It redirects correctly, but doesn't update.
in the invoices controller:
def invoice_params
params.require(:invoice).permit(:invoice_number, :customer_id, :invoice_date, :invoice_status_id, :employee_id, invoice_products_attributes: [:id, :invoice_id, :product_id, :price, :tax, :discount, :value])
end
Can anyone please help me in identifying where I am going wrong? Could it be my approach is not even valid?
Thanks in advance
The type of functionality you're after is considered "business logic" and should be implemented in the model and called from the controller.
You can define a method in a model:
class Invoice < ActiveRecord::Base
def update_invoice(cust_id, emp_id)
if self.update_attributes(:customer_id => cust_id], :employee_id = emp_id])
puts "Success!
else
puts "Failed to update record. Handle the error."
end
end
You can call my_method from carts_controller.rb like this:
def update
# all your regular update logic here
# replace the bit of code that saves the cart with something like this:
respond_to do |format|
if(current_invoice.update_invoice(params[:customer_id], params[:employee_id])
if(#cart.update(cart_params))
format.html { redirect_to #activity, notice: 'Activity was successfully updated.' }
format.json { render :show, status: :ok, location: #activity }
else
format.html { render :edit }
format.json { render json: #activity.errors, status: :unprocessable_entity }
end
end
end
Also, note the use of update_attributes rather than save. Bear in mind that update_attributes will return false if you run into any problems updating (e.g. one or more validations failed). Don't confuse update_attributes with the singular update_attribute which updates a single field and will not run validations.
Finally got it.
current_invoice.update_attributes(customer_id: params[:invoice][:customer_id], employee_id: params[:invoice][:employee_id])
Also in view, changed location of form_tag:
<div class = "row">
<%= form_tag carts_checkout_path, method: :post do |f| %>
<div class = "col-lg-3 col-lg-offset-6 text-left">
<strong>Cliente: </strong>
<%= collection_select(:invoice, :customer_id, #customers, :id, :full_name, {:prompt => 'Favor Seleccionar'}, class: 'form-control') %>
</div>
<div class = "col-lg-3 ext-left">
<strong>Vendedor: </strong>
<%= collection_select(:invoice, :employee_id, #employees, :id, :full_name, {:prompt => 'Favor Seleccionar'}, class: 'form-control') %>
</div>
<div class = "col-lg-12 text-right">
<%= submit_tag 'Completar', class: 'btn btn-success' %>
</div>
<% end %>
</div>
Could it be my approach is not even valid
Your approach is definitely valid, it's great that you're using sessions in this way.
I'd do it slightly differently:
#config/routes.rb
resource :cart, except: [:edit, :new, :create], path_names: { update: "checkout" }
This will give you the following paths:
#url.com/cart -> carts#show (here you can invoke a cart if one doesn't exist)
#url.com/cart/checkout #-> POST to "update" method in carts controller
#url.com/cart/ (method: :delete) -> DELETE to "destroy" cart (refresh)
--
#app/controllers/carts_controller.rb
class CartsController < ApplicationController
before_action :setup_cart
def show
#cart = current_cart #-> products called from this. I don't know how you're linking them
#customers = Customer.all
#employees = Employee.all
end
def update
#invoice = Invoice.find_or_create_by(id: current_card.id)
#invoice.update update_params
redirect_to cart_path
end
def destroy
current_cart = nil
redirect_to carts_path, notice: "Cart Cleared"
end
private
def setup_cart
current_cart ||= sessions[:cart]
end
def update_params
params.require(:cart).permit(:customer_id, :employee_id)
end
end
Now, to update the cart, you'll want to take note from MarsAtomic's answer. However it must be noted that naked params are not available in the model.
If you use update_attributes, or just plain update, you'll need to do the following:
#app/models/cart.rb
class Invoice < ActiveRecord::Base
has_many :products
belongs_to :employee
belongs_to :customer
#validations here
#callbacks here (what MarsAtomic refers to as business logic)
before_save :do_something, only: :update
private
def do_something
#something here
#params appended to current instance of object
#eg self.customer_id
end
end
I'd also go more succinct in your view:
#app/views/carts/show.html.erb
<div class = "row">
<%= form_tag cart_checkout_path, method: :patch do |f| %>
<% options = [["cliente", "customer"], ["vendedor", "employee"]] %>
<% options.each do |name, type| %>
<%= content_tag :strong, "#{name.titleize}:" %>
<%= collection_select :cart, eval(":#{type}_id"), instance_variable_get("##{type.pluralize}"), :id, :full_name, {:prompt => 'Favor Seleccionar'}, class: 'form-control') %>
<% end %>
<% content_tag :div, class: "col-lg-12 text-right" do %>
<%= submit_tag 'Completar', class: 'btn btn-success' %>
<% end %>
<% end %>
</div>

Error: param is missing or the value is empty: thing

I'm using rails 4.0.8. I added a comment section to a model called 'Things', but I keep getting the same error "param is missing or the value is empty: thing" when I press the submit comment button. It says the error is in the Things#Controller. What am I doing wrong?
UPDATE: I removed the url path from the form, but a new error returns "Couldn't find Thing without an ID". The error is in Comments#Controller.
VIEW FOR THING/SHOW
<div id= "thing">
<h1>
<%= #thing.name %>
</h1>
<br>
<div id= "commentsection">
Comments
<div id= "comments">
<br>
<% #thing.comments.each do |c| %>
<%= c.username %>
<br>
<%= c.text %>
<% end %>
<%= form_for #comment, :url => thing_path do |f| %>
<%= f.label :username %>
<%= f.text_field :username %>
<%= f.label :comment %>
<%= f.text_field :text %>
<%= f.submit "Enter", class: "btn btn-small btn-primary" %>
<% end %>
</div>
</div>
</div>
THINGS CONTROLLER
class ThingsController < ApplicationController
def show
#thing = Thing.find(params[:id])
#thing.comments.build
#comment = Comment.new
end
def index
end
def new
#thing = Thing.new
#things = Thing.all
end
def create
#thing = Thing.new(thing_params)
if #thing.save
redirect_to #thing
else
render 'new'
end
end
private
def thing_params
params.require(:thing).permit(:name, :avatar)
end
end
COMMENTS CONTROLLER (I put asterisks around the line where the error is)
class CommentsController < ApplicationController
def show
#comment = Comment.find(params[:id])
end
def new
#comment = Comment.new
#comments = Comment.all
end
def create
****#thing = Thing.find(params[:thing_id])****
#comment = #thing.comments.create(comment_params)
redirect_to thing_path(#thing)
end
end
private
def comment_params
params.require(:comment).permit(:user, :text, :upvotes, :downvotes, :thing_id)
end
end
ROUTES
Website::Application.routes.draw do
get "comments/new"
get "comments/show"
get "things/new"
root 'home_page#home'
get "all/things/new" => 'things#new'
get "all/allthings"
resources :things
resources :good_comments
get "things/show"
get "things/results"
end
You are posting the #comment form to post '/things' path.
<%= form_for #comment, :url => thing_path do |f| %>
It should just be <%= form_for #comment do %> (Rails is smart enough to plug in the comments_path) or if you feel like being more explicit (even though it's not necessary)
<%= form_for #comment, url: :comments_path do %>
Another note though, if you want that Comment to be tied to that specific Thing then in your models it should be
Class Thing
has_many :comments
end
Class Comment
belongs_to :thing
end
Then make sure in your database comment has a thing_id foreign_key field and then your form for comment should actually look like
<%= form_for #thing, #comment do %>
<% end %>

undefined method `home_home_path'

I am new to rails development and still trying to understand the building blocks of it. While running this simple code, I am getting following error
undefined method `home_home_path'
it is coming from this line <%= form_for(#homes) do |f| %> in .html.erb file. Here is my complete code, what I am doing wrong ?
I have Homes Controller file
def index
#homes = Home.all
end
def show
#home = Home.find(params[:id])
end
def new
#home = Home.new
end
def create
#home = Home.new(params[:home])
#home.save
end
Homes.rb model file
class Home < ActiveRecord::Base
attr_accessible :email, :message, :name
end
views/homes/index.html.erb
# this will show all the data
<% #homes.each do |home| %>
<%= home.name %><br />
<%= home.email %> <br />
<%= home.message %><br />
<% end %>
<br />
# this is a form where you will new records
<%= form_for(#homes) do |f| %>
<%= f.text_field :name %>
<%= f.text_field :email %>
<%= f.text_area :message %>
<%= f.submit %>
<% end %>
You should use :
<%= form_for(#home) do |f| %>
(singular)
And if you want to add a form in your index.html , remember to instantiate a new home object in your controller index method :
def index
#homes = Home.all #For displaying all the homes
#home = Home.new #For your form
end
#homes is an array object. I'm not really sure how Rails infers the url from this but running
url_for Home.limit(2).all
will also give you the same error.
The solution is to change #homes to Home.new or declare #home = Home.new in your controller and use #home in the form.
form_for Home.new
or
# controller
def index
#homes = Home.all
#home = Home.new
end
# view
form_for #home

Resources