Setting the params:id issue - ruby-on-rails

I am editing the index.html.erb page in the sources view
<% #sources.each_slice(20) do |s| %>
<div class="span3">
<% s.each do |i| %>
<div><%= link_to(truncate(i.name, :length => 30) , sources_path(i.id), :class => 'action show') %></div>
<% end %>
</div>
<% end %>
The sources.controller is..
def index
#sources = Source.search(:search=>params[:search])
respond_to do |format|
format.html # index.html.erb
format.json { render json: #sources }
end
end
Q: When the params[:search] is valid. Why does the i.name info get presented and the i.id doesn't...How can I get the i.id?

It's probably not related to the id, it's most likely related to the fact that you're using sources_path instead of using source_path.

Related

Rails 4 : Table Boolean Column Update Using "link_to "with a specific value "TRUE" always

In my customer controller the update method code is like bellow:
def update
#customer= Customer.find(params[:id])
if #customer.update_attributes(customer_params)
redirect_to customers_path
else
render 'edit'
end
end
In my view in customers index page I am planning to add a "link_to" link, if it is clicked, then that particular customers field "doc_delete" should be updated with value "TRUE".
<td><%= link_to "[Update", *************what is here ?******** method: :put %></td>
You can pass hidden params through button_to:
<%= button_to "Update", user, method: :put, params: { doc_delete: true } %>
This will create a micro-form, much like what Marwen alluded to. Whilst quite inefficient, it will be the best way to send data to your update action.
--
Another, more efficient, way would be to define a custom route/action:
#config/routes.rb
resources :customers do
patch :doc_delete, on: :member #-> url.com/users/:id/doc_delete
end
#app/controllers/customers_controller.rb
class CustomersController < ApplicationController
def doc_delete
#customer = Customer.find params[:id]
redirect_to customers_path if #customer.update doc_delete: true
end
end
#app/views/customers/index.html.erb
<% #customers.each do |customer| %>
<%= link_to "Update", customer_doc_delete_path(customer) %>
<% end %>
You will need a form to do that for you
<% unless customer.doc_delete? %>
<%= form_for customer do |f| %>
<%= f.hidden_field_tag :doc_delete, true %>
<%= f.submit %>
<% end %>
<% end %>
Where to insert this form?
Well if you are rendering you costumers using:
<%=render #costumers %>
then you will add the form in the /customers/_customer.html.erb
If you are looping them manually:
<% #customers.each do |customer| %>
<%=customer.full_name %>
## Here you can add the form
<% end %>
An another way, you can use Ajax.
#app/views/customers/index.html.erb
<% #customers.each do |customer| %>
<% if !customer.doc_delete == true %>
<%= link_to "Update", customer_doc_delete_path(customer), remote: true %>
<% else %>
<%= Updated %>
<% end %>
<% end %>
#config/routes.rb
resources :customers do
patch :doc_delete, on: :member #-> url.com/customers/:id/doc_delete
end
#app/controllers/customers_controller.rb
class CustomersController < ApplicationController
def doc_delete
#customer = Customer.find params[:id]
if #customer.update doc_delete: true
respond_to do | format |
format.js {render :nothing => true}
end
end
end
end
In my index.html
<td>
<%= hidden_field_tag 'delete_present', :value => "present" %>
<%=link_to "[update]", customer_path(customer, :doc_delete => true), :method => :put, :confirm => "Are you sure?" %>
</td>
In my customer controller
def update
if params[:doc_delete].present?
#customer= Customer.find(params[:id])
#customer.doc_delete=true
#customer.save
redirect_to customers_path
else
#customer= Customer.find(params[:id])
if #customer.update_attributes(customer_params)
redirect_to customers_path
else
render 'edit'
end
end
end

How to redirect two buttons on a different path with the same action?

I try to create discount coupons subtracting total basket of my customers.
I'm not sure it's the best way to do it but I created a solution that works almost.
The only problem is that when I create coupon, I can't render the same page because my order's update method redirect to the checkout page. I want to different redirections, one for checkout when the customer click on the checkout button on my cart page, the other when the customer create a coupon on the same cart page. The two buttons uses the same update action.
Any idea how to solve it ?
Here's my orders_controller:
def update
#order = current_order
update_coupon
if #order.update(order_params)
redirect_to checkout_path
else
render 'new'
end
end
private
def update_coupon
if #order.update(:coupon => params[:order])
redirect_to cart_path
end
end
Here's my carts/show.html.erb:
<p>Total TTC: <%= number_to_currency #order.subtotal %></p>
<% if #order.add_reduc.nil? %>
<% else %>
<p style="color:green;">-<%= number_to_currency #order.add_reduc, id: "new_reduc" %></p>
#set coupon value to nil
<%= form_for #order do |f| %>
<%= f.hidden_field :coupon, :value => nil %>
<%= f.submit "x" %>
<% end %>
<p>Price after reduction: <%= number_to_currency #order.subtotal_with_reduc %></p>
<p style="color:green;"><%= #order.coupon_description %></p>
<% end %>
<%= form_for #order do |f| %>
<%= f.text_field :coupon, placeholder:'place your coupon' %>
<%= f.submit "Go coupon" %>
<% end %>
and my order.rb :
COUPONS = {
'MAREDUC' => '25% off',
'CHOCOLOVER' => '10€ free',
'PAPLAFUN' => '10% off'
}
def subtotal_all_inclusive
if self.add_reduc.nil?
subtotal + shipping
else
subtotal_with_reduc + shipping
end
end
def coupon_description
COUPONS[coupon]
end
def add_reduc
if self.coupon == "MAREDUC"
subtotal * 25 / 100
elsif self.coupon == "CHOCOLOVER" && self.subtotal >= 50
10
elsif self.coupon == "PAPLAFUN"
subtotal * 10 /100
else
nil
end
end
You may add a hidden field in the coupon form:
<%= form_for #order do |f| %>
<%= hidden_field_tag :from_coupon, 1 %>
<%= f.text_field :coupon, placeholder:'place your coupon' %>
<%= f.submit "Go coupon" %>
And then:
def update
#order = current_order
if params[:from_coupon]
update_coupon
else
if #order.update(order_params)
redirect_to checkout_path
else
render 'new'
end
end
end
Or you may create an additional action in routes.rb:
resources :orders do
member do
put 'update_coupon'
end
end
And then:
<%= form_for #order, :url => update_coupon_order_path(#order), :method => :put do |f| %>
And then remove private in controller.
Pass additional param to url and check if it present make different actions. Example
<%= form_for #order, url: order_path(#order, additional: "your_param") do |f| %>

pass array hidden field in nested model rails

I have following code in my view:
<% #m1.map(&:id).each do |id|%>
<%= b.fields_for :modul1hours do |f| %>
<%= f.hidden_field :modul1_id, id %>
<%= f.text_field :module_est_hours, :size => 30 %>
</tr>
<% end %>
<%end%>
params passing in console
Parameters: {"authenticity_token"=>"LJ/ZME2lHZ7VwCDgPKX6OFe326fXSXo5UB4M0cPwbCE=", "esthour"=>{"rfp_id"=>"6", "ecommerce_est_hours"=>"", "modul1hours"=>{"module_est_hours"=>"3"}, "designpages_est_hours"=>"", "cms_est_hours"=>""}, "modul1_ids"=>["12", "13", "14"], "utf8"=>"✓", "project_id"=>"second", "commit"=>"Add Todo"}
Current user: admin (id=1)
modul1_ids is the hidden array based on that three text box is created but when i submit the page gives me:
ActionView::Template::Error (undefined method `merge' for 12:Fixnum):
in first textbox i passed 1
second 2
and in third 3
last value(3) isthe s passing that one can see in the console params module_est_hours"=>"3, but what about rest two fields y not passing and whats the solution for an error. Please help me.
Edit 1
<% #m1.map(&:id).each do |id|%>
<%= b.fields_for :modul1hours do |f| %>
<%= hidden_field_tag "modul1_ids[]", id %>
<%= f.text_field :module_est_hours, :size => 30 %>
</tr>
<% end %>
<%end%>
this code does not give the error, but also value is not stored in modul1hours table
The field of the modul1hours table are:
integer :modul1_id
decimal :module_est_hours
decimal :module_act_hours
integer :esthours_id
]
.rb
belongs_to :esthour
attr_accessible :module_est_hours,:module_act_hours
and controller
Update
def new
#esthour = Esthour.new
#gg = #esthour.modul1hours.build
#project = params[:project_id]
#rfp = params[:rfp_id]
#m1 = Modul1.where(:rfp_id => #rfp.id)
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #esthour }
end
end
over Update
# GET /project_todos/1/edit
def edit
#esthour = Esthour.find(params[:id])
end
def create
#project = params[:project_id]
#esthour = Esthour.new(params[:esthour])
user_params = params.select{|k,v| k.include?('esthour')}
respond_to do |format|
if #esthour.save
get_issue_attribute_param1(user_params)
format.html { redirect_to project_rfp_url(#project,#esthour.rfp_id), :notice => 'hours was successfully created.' }
format.json { render :json => #esthour, :status => :created, :location => #esthour }
else
format.html { render :action => "new" }
format.json { render :json => #esthour.errors, :status => :unprocessable_entity }
end
end
end
is there any build needed?eg Esthour.modul1hour.build in new def of controller coz record not saved in table?
view
<%= form_for #esthour,:rfp_id => #rfp.id,:project_id => #project do |b| %>
<%= b.hidden_field :rfp_id, :value => #rfp.id %>
<%= hidden_field_tag :project_id, #project %>
<table>
<tr> <td><b>Menutype </b></td>
<% if #rfp.menutype.present? %>
<td><%= #rfp.menutype %></td>
<td><%= b.number_field :menutype_est_hours %></td>
<% end %>
</tr>
<tr> <td> <b>Number of menu</b> </td>
<% if #rfp.numberofmenu.present? %>
<td><%= #rfp.numberofmenu %></td>
<td><%= b.number_field :numberofmenu_est_hours %></td>
<% end %>
</tr>
<tr>
<% #m1.map(&:id).each do |id|%>
<%= b.fields_for :modul1hours do |f| %>
<%= f.hidden_field :modul1_id, value => id %>
<%= f.text_field :module_est_hours, :size => 30 %>
</tr>
<% end %>
<% end %>
</table>
<%= b.submit 'Add Todo' %>
<% end %>
#esthour = Esthour.new
#gg = #esthour.modul1hours.build
#project = params[:project_id]
In this line:
<%= f.hidden_field :modul1_id, id %>
You are saying that you want the hidden field binded with modul1hour modul1_id method and options being id. Second parameter for FormBuilder hidden_field is expected to be a hash (which is then merged against default options). To do what you want do:
<%= f.hidden_field :modul1_id, value: id %>
Hidden fields aren't really the issue here
Apart from #BroiStatse's answer, I can see the issue as how you handle the params on your controller
Nested Models
Sending data to a controller sends that data to the relevant models. This is normally handled with accepts_nested_attributes_for, but can be handled manually too
From your controller code, I can't see how you're dealing with your extra data, but your error is caused by the incorrect merge of the params
Instead of saving the data manually, I would use the accepts_nested_attributes_for to save the data, like this:
#app/models/project.rb
Class Project < ActiveRecord::Base
accepts_nested_attributes_for :modul1hours
end
This will pass the params to your modul1hours model, where you'll then have to capture them with the relevant attr_accessible actions
f.fields_for
In order to get accepts_nested_attributes_for working properly, you have to ensure you use the f.fields_for function correctly.
You have to first build the ActiveRecord objects in your new controller action, like this:
def new
#project = Project.new
#project.modul1hours.build
end
Your problem is that you're then cycling through the ID's of your modul1hours model, yielding the f.fields_for artificially. Rails will only output an f.fields_for if the ActiveRecord object has been built in the controller:
"30" %>
This RailsCast gives you a better idea about this
What I would do is this:
#app/controllers/projects_controller.rb
def new
#project = Project.new
#m1.map(&:id).each do |i|
#project.modul1hours.build
end
end
#app/views/projects/new.html.erb
<%= b.fields_for :modul1hours do |f| %>
<%= hidden_field_tag :id, value :id %>
<%= f.text_field :module_est_hours, :size => "30" %>
<% end %>
I'm still thinking about how I would assign the ID's to the hidden field
Update
Try this:
#app/controllers/projects_controller.rb
def new
#project = Project.new
#project.modul1hours.build
end
Replace modul1hours with whatever your projects has_many of

Rails: Ajax for Like Button and Updating Like Count

I am able to update the like and unlike button via ajax, but I am not able to update the like count.
Post has_many likes
likes_controller.rb
def create
#like = Like.new(:post_id => params[:post_to_be_liked])
if #like.save
respond_to do |format|
format.html {redirect_to :back, notice: "Liked!"}
format.js
end
end
end
view.html.erb
<% #post = user.posts.first %>
<div id="send_like_for_<%= #post.id %>">
<% if #post.is_liked?(#post, current_user)%>
<%= render 'unlike'%>
<%else%>
<%= render 'like'%>
<%end%>
</div>
<div id="liked_<%= #post.id %>" %>
<%= render 'liked_users'%>
</div>
create.js.erb
$("#send_like_for_<%= params[:post_to_be_liked]%>").html("<%= escape_javascript(render('users/unlike')) %>")
$("#liked_<%= params[:post_to_be_liked]%>").html("<%= escape_javascript(render('users/liked_users')) %>")
_like.html.erb
<%= link_to "LIKE", likes_path(:post_to_be_liked => #post.id), remote: true, :method=>:post %>
_unlike.html.erb
<span> UNLIKE </span>
_liked_users.html.erb
<%= "#{#post.likes.length} like this" %>
The like/unlike functionality works just fine and when someone likes the post the button changes to Unlike. But the like count doesn't increase.
But why are you doing this in your view?
<% #post = user.posts.first %>
It will update only your first post always. I can't understand.
Try with this:
_liked_users.html.erb
<%= #updated_post = Post.where(id: #post.id) %>
<%= "#{#updated_post.likes.length} like this" %>
or
<%= #post.reload %>
<%= "#{#post.likes.length} like this" %>
Edit (Try to build your like this):
def create
#post = Post.where(id: params[:post_to_be_liked])
#like = #post.likes.build(:post_id => #post.id)
if #like.save
respond_to do |format|
format.html {redirect_to :back, notice: "Liked!"}
format.js
end
end
end
I think you should try to do this
#post = user.posts.first
after save in your controller and remove <% #post = user.posts.first %> from erb file and if it is not possible then initialize #post in your controller#create
#post = Post.find(params[:post_to_be_liked])

Adding to database without refreshing the page?

When I add a model in my index action, the create action is invoked that adds an instance of the model to the database. This is the following create action:
tracks_controller.rb
def create
#track = Track.new(params[:track])
if #track.save
redirect_to(root_url) //Want to change this!
else
#tracks = Track.all
render :action=>"index"
end
end
Where you can see that I am redirected to my root url (where I want to be) everytime create is invoked. However, how can I carry this out without refreshing the page? Since tracks are being played, I do not want the page to be refreshed whenever something is added to the database.
If I change this line to render :action=>"index", then I receive the following error in my index.html.erb file
undefined methodeach' for nil:NilClass`
15: <p>Database is empty!</p>
16: <%else%>
17: <br>
18: <% #tracks.each do |track| %>
19: <div id="list_container">
20: <ul>
21: <li class="list_container">
How do I go about achieving this?
form
<%= form_for #track, remote: true %>
form fields
<%= f.submit %>
<% end %>
app/views/tracks/create.js.erb
<% if #track.valid? %>
  $(".tracks").prepend('<%= j(render(#track)) %>'); // make sure you have _track.html.erb
$("ID OR CLASS OF YOUR FORM")[0].reset(); // this will clear your form inputs
<% else %>
alert('Something Went Wrong');
<% end %>
app/views/tracks/index.html.erb
<div class="tracks">
<% #tracks.each do |track| %>
<%= render :partial => 'track' %>
<% end %>
</div>
app/views/tracks/_track.html.erb
some code here to show track:
<div>track.id</div>
<div>track.name</div>
index.html.erb needs the #tracks variable. Therefore, you have to set it before rendering the page.
For example:
def create
#track = Track.create(params[:track])
#tracks = Track.all
render :action => "index"
end
The simplest, quickest way to get it is to add :remote => true to you form_for!
If you are posting track from a form then make the remote to true
like
<%=form_for #track, :remote => true do |f| %>
your input fields
<%end %>
index.html.erb
<div id="track_list">
<%= render :partial => 'tracks_record' %>
</div>
_tracks_record.html.erb
<% #tracks.each do |track|%>
your code
<% end %>
in controller
def create
#track = Track.create(params[:track])
#tracks = Track.all
respond_to do |format|
format.js
end
end
Create one js.erb file for create.js.erb
<% if #track.valid? %>
('#track_list').html('<%= escape_javascript( render :partial => "tracks_record" ) %>');
<% else %>
alert('Could not save');
<% end %>
This will refresh the data and populate the new entries without refreshing the page.
Unfortunately I can't comment on Debadatt's suggestion but I found it much better than the top post. My only notes are to change this to
def create
#track = Track.create(params[:track])
#tracks = Track.all
respond_to do |format|
format.js
end
end
to this:
def create
#track = Track.create(params[:track])
#tracks = Track.all
respond_to do |format|
format.js { render layout: false, content_type: 'text/javascript' }
end
end
And this:
('#track_list').html('<%= escape_javascript( render :partial => "tracks_record" ) %>');
to this:
$('#track_list').html('<%= escape_javascript( render :partial => "tracks_record" ) %>');
Great suggestion thanks Debadatt

Resources