So I have a Rails app with posts and categories, and as I'm having the website tested out by friends I realized I forgot to add any pagination to category pages, so once a lot of listings are added the page just keeps getting longer and longer which is obviously not ideal.
Here's the code on each category page that renders the listings:
<% notsold = #category.products.where("sold_value = false").order("created_at DESC") %>
<% notsold.each do |f| %>
<% if User.find(f.user_id).school == current_user.school %>
<div class="listing">
<%= image_tag User.find(f.user_id).avatar.url(:thumb).sub('http://s3.amazonaws.com/anymarket/','http://anymarket.s3.amazonaws.com/'), :id => "categories_profile_picture", :width => "30", :height => "30" %><h4><%= link_to f.name, view_item_path(f.id) %></h4><% if f.photo? %><span id="camera-icon-preview" class="glyphicon glyphicon-camera preview_toggle" data-id="<%= f.id %>"></span><% else %><% end %><p><%= f.description[0..60].gsub(/\s\w+\s*$/, '...') %></p><p class="price"><%= number_to_currency(f.decimal_price, precision: 2) %></p>
</div>
<% else %>
<% end %>
<% end %>
Div#listing is each individual listing.
The problem is I don't know how to preserve this code and add pagination. I'm looking for some advice on how to do this.
You can use the will_paginate gem
example from page:
In your controller like this:
#posts = Post.paginate(:page => params[:page])
more examples:
## perform a paginated query:
#posts = Post.paginate(:page => params[:page])
# or, use an explicit "per page" limit:
Post.paginate(:page => params[:page], :per_page => 30)
## render page links in the view:
<%= will_paginate #posts %>
Not sure but this should work out for you:
<% notsold = #category.products.where("sold_value = false").order("created_at DESC").paginate(:page => params[:page], :per_page => 30) %>
<% notsold.each do |f| %>
<% if User.find(f.user_id).school == current_user.school %>
<div class="listing">
<%= image_tag User.find(f.user_id).avatar.url(:thumb).sub('http://s3.amazonaws.com/anymarket/','http://anymarket.s3.amazonaws.com/'), :id => "categories_profile_picture", :width => "30", :height => "30" %><h4><%= link_to f.name, view_item_path(f.id) %></h4><% if f.photo? %><span id="camera-icon-preview" class="glyphicon glyphicon-camera preview_toggle" data-id="<%= f.id %>"></span><% else %><% end %><p><%= f.description[0..60].gsub(/\s\w+\s*$/, '...') %></p><p class="price"><%= number_to_currency(f.decimal_price, precision: 2) %></p>
</div>
<% else %>
<% end %>
<% end %>
Related
I am using a theme that has very specific layouts and I wanted to make a failsafe way to you rails forms.
I have a layout app/views/shared/forms/fields/_layout.html.erb
<div class="js-form-message mb-4">
<div class="js-focus-state input-group u-form">
<div class="input-group g-brd-primary--focus">
<%= yield(:field) %>
</div>
</div>
</div>
And I have two partials.
1-st partial: app/views/shared/forms/fields/_email.html.erb
<% form = locals[:form] %>
<% locals[:required] = locals[:required].nil? ? true : locals[:required] %>
<% locals[:placeholder] = locals[:placeholder] || t('forms.shared.email.placeholder') %>
<%= render layout: "shared/forms/fields/layout", locals: locals do %>
<% content_for(:field) do %>
<%= form.email_field :email,
placeholder: locals[:placeholder],
class: "form-control g-py-15 g-px-15",
"data-error-class"=>"u-has-error-v1-3",
"data-success-class"=>"u-has-success-v1-2",
"data-msg-email" => t('forms.shared.email.validate'),
"data-msg" => t('forms.shared.required'),
autofocus: locals[:autofocus],
required: locals[:required] %>
<% end %>
<% end %>
2-nd partial: app/views/shared/forms/fields/_login.html.erb
<% form = locals[:form] %>
<% locals[:required] = locals[:required].nil? ? true : locals[:required] %>
<% locals[:placeholder] = locals[:placeholder] || t('forms.shared.login.placeholder') %>
<%= render layout: "shared/forms/fields/layout", locals: locals do %>
<% content_for(:field) do %>
<%= form.email_field :login,
placeholder: locals[:placeholder],
class: "form-control g-py-15 g-px-15",
"data-error-class"=>"u-has-error-v1-3",
"data-success-class"=>"u-has-success-v1-2",
"data-msg" => t('forms.shared.required'),
autofocus: locals[:autofocus],
required: locals[:required] %>
<% end %>
<% end %>
And when I do this:
<%= render "shared/forms/fields/email", locals: {form: f} %>
<%= render "shared/forms/fields/login", locals: {form: f} %>
I get
Email Field
Email Field/Login Field
I found out that content_for 'appends' the block that you give it and then when I yield the whole block is returned.
The first time there is nothing in content_for(:field) and it appends to it Email Field. But the second time it does not clear its content and just appends Login Field to it.
I am thinking of adding additional complexity to layout.html.erb so just keeping it inline isn't an option.
Is there a way to tell to the layout only to yield the 'newest' value of content_for.
EDIT:
I wrote a method to flush after an yield, suggesting that the same key would be used again:
def yield_and_flush!(content_key)
view_flow.content.delete(content_key)
end
content_for has flush option to reset previous content:
<% content_for :field, flush: true do %>
new content here
<% end %>
The solution was this to write an yield_and_flush! method. I saw the solution here
def yield_and_flush!(content_key)
view_flow.content.delete(content_key)
end
Hi i want to send the selected object to a controller method but I dont know how. this is the select list with the vaules in it
Html------------
<%= form_tag '/wendy' do %>
<%= select_tag :'buenwendy', options_from_collection_for_select(#cursitos, 'id', 'name') %>
<%= submit_tag 'buscar', class: 'btn btn-success' %>
<% end %>
routes.rb
post 'wendy', to: 'blog#wendy
Controller------------------------------
def wendy
gg= params[:buenwendy]
flash[:success]= gg
redirect_to root_path
end
try this: after selecting course you will get can find that course at controller side and storing it in #gg variable
HTML...........
<%= form_tag( '/wendy', :method => :post ) %>
<%= select_tag :'buenwendy', options_from_collection_for_select(#cursitos, 'id', 'name') %>
<%= submit_tag 'buscar', class: 'btn btn-success' %>
<% end %>
......routes
post '/wendy', to: 'blog#wendy
controller..........
def wendy
#gg= Course.find(params[:buenwendy])
flash[:success]= #gg
redirect_to root_path
end
I solved it guys, I had to get the id of #cursitos from the SQL query
#cursitos = Course.find_by_sql("SELECT *courses.id*, courses.name FROM courses, cours_sts, students WHERE courses.id = cours_sts.course_id AND students.id = cours_sts.student_id AND students.id= 1")
So i am getting trouble in saving form data,.Any help will b appreciable
form is submitted without getting any error, but in database, nothing is stored
i am new on rails
users_controller
class UsersController < ApplicationController
def new
#user= User.new
end
def create
#user = User.new(params[:User])
if #user.save
flash[:notice]= "you signed up successfully"
flash[:color]= "valid"
else
flash[:notice]= "failed"
flash[:color]="invalid"
end
render "new"
end
end
new.html.erb
<% page_title="Signup" %>
<div class="Sign_Form">
<h1>Sign up</h1>
<%= form_for(:user, :url => {:controller => 'users', :action => 'create'}) do |f| %>
<p> Username:</br> <%= f.text_field :username %> </p>
<p> Email:</br> <%= f.text_field :email %> </p>
<p> Password:</br> <%= f.password_field :password %></p>
<p> Password Confirmation:</br> <%= f.password_field :password_confirmation %> </p>
<%= f.submit :Signup %>
<% end %>
<% if #user.errors.any? %>
<ul class="Signup_Errors">
<% for message_error in #user.errors.full_messages %>
<li>* <%= message_error %></li>
<% end %>
</ul>
<% end %>
</div>
in app/models/user.rb
class User < ActiveRecord::Base
attr_accessor :password
EMAIL_REGEX = /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i
validates :username, :presence => true, :uniqueness => true, :length => { :in => 3..20 }
validates :email, :presence => true, :uniqueness => true #:format => EMAIL_REGEX
validates :password, :presence =>true #:confirmation => true #password_confirmation attr
validates_length_of :password, :in => 6..20, :on => :create
end
In users_controller, create method, you are using
#user = User.new(params[:User])
replace it with following code, hope it will work fine.
#user = User.new(params[:user])
And,also use strong params if you are using rails 4. Like follwoing.
def create
#user = User.new(user_params)
if #user.save
flash[:notice]= "you signed up successfully"
flash[:color]= "valid"
else
flash[:notice]= "failed"
flash[:color]="invalid"
end
render "new"
end
private
def user_params
params.require(:user).permit(:username, :account, :email, :password, :password_confirmation)
end
If, it still not works, then, please display your log.
If you are using Rails 4 you need to use strong parameters to whitelist the parameters you want to assign to your models.
This became non-optional in Rails 4 to prevent mass-assignment vulnerabilities where a malicious user can assign any property to a model after Egor Homakovs much publicised Github attack.
Also note that Ruby is case sensitive. This applies to hash keys as well:
irb(main):003:0> hash = { a: 1 }
=> {:a=>1}
irb(main):004:0> hash[:A]
=> nil
Which is why why you do User.new(params[:User]) you are actually doing User.new(nil)
This is a corrected version of your controller
class UsersController < ApplicationController
def new
#user= User.new
end
def create
#user = User.new(params[:User])
if #user.save
flash[:notice]= "you signed up successfully"
flash[:color]= "valid"
# You should redirect instead of rendering the form again
redirect_to #user # or redirect_to root_path
else
flash[:notice]= "failed"
flash[:color]="invalid"
render "new" # Needs to be inside the "else" statement
# Otherwise you will get a double render error
end
end
def user_params
params.require(:user)
.allow(:username, :email, :password, :password_confirmation)
end
end
Added:
You can also simplify your form_for to
<%= form_for(:user) do |f| %>
Rails will by convention route the form to UserController#create.
Also you should use <label> tags for accessibility, as they help people who use assistive technology such as screen readers to find the correct inputs.
By using the built in label helper rails will set up the for attribute and you can translate the label texts with Rails built in I18n functionality.
<% page_title="Signup" %>
<div class="Sign_Form">
<h1>Sign up</h1>
<%= form_for(:user) do |f| %>
<div class="row">
<%= f.label :username %>:</br>
<%= f.text_field :username %>
</div>
<div class="row">
<%= f.label :email %>:</br>
<%= f.text_field :email %>
</div>
<div class="row">
<%= f.label :password %>:</br>
<%= f.password_field :password %>
</div>
<%= f.submit :Signup %>
<% end %>
<% if #user.errors.any? %>
<ul class="Signup_Errors">
<%# for loops are almost never used in ruby. %>
<%# .each is the idiomatically correct way %>
<% #user.errors.full_messages.each do |message_error| %>
<li>* <%= message_error %></li>
<% end %>
</ul>
<% end %>
</div>
I'm working with Ruby on Rails, trying to get my search bar to display the results. I've tried searching for similar issues, but most already had search working and weren't getting it to work right.
in my html I have:
<%= form_tag users_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
<div class="scrollBox">
<%= will_paginate%>
<ul>
<% #users.each do |user| %>
<li>
<%= link_to user.name, user, {:class=>"signout-style"} %>
</li>
<% end %>
</ul>
<%= will_paginate %>
</div>
In my users controller I have:
def index
#users = User.paginate(page: params[:page])
#searches = User.search(params[:search])
end
In my users model I have:
def self.search(search)
if search
find(:all, :conditions => ['name LIKE ?', "%#{search}%"])
else
find(:all)
end
end
I was using the railscast episode #37
Any help is appreciated!
Update the index action as below:
def index
#users = User.search(params[:search]).paginate(page: params[:page])
end
Currently, you are storing the search results in instance variable #searches with this line:
#searches = User.search(params[:search])
BUT in your view you are accessing #users which is set as #users = User.paginate(page: params[:page]). So, you always see all the users in the view and not the searched users.
UPDATE
As you are using Rails 4.0.2, I would suggest you to refactor your search method as below:
def self.search(search)
if search
where('name LIKE ?', "%#{search}%")
else
all
end
end
I seem to be having a problem with receiving products through my join table, it's giving me a strange error as it seems to be receiving no ID for my order. I can only assume that this is because the order has not been created yet, but I am creating the order during this step anyway, so the order doesn't have an ID yet. So this is my problem.
Here is the error I recieve:
ActiveRecord::RecordNotFound in OrdersController#create
Couldn't find Product with ID=1 for Order with ID=
Rails.root: /BillingSystem
Application Trace | Framework Trace | Full Trace
app/controllers/orders_controller.rb:10:in `new'
app/controllers/orders_controller.rb:10:in `create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"jE2wdERoxE7PKwBhN60KAfguxwAq8qdW4wbru51SMFg=",
"order"=>{"client_id"=>"1",
"products_attributes"=>{"1368396234677"=>{"id"=>"1",
"_destroy"=>"false"}}},
"commit"=>"Create Order"}
Show session dump
Show env dump
Response
Headers:
None
New Order View:
<% if current_user %>
<div id="dashboard">
<div id="logo"></div>
<table id="go_back_link_container">
<tr>
<td>
<div class="go_back_link">
<%= link_to "<- Go Back", "/orders/view" %>
</div>
</td>
<td>
<div id="user_display">
Logged in as <%= current_user.email %>.
<%= link_to "Log out", log_out_path %>
</div>
</td>
</tr>
</table>
<%= form_for #order, method: :post do |f| %>
<% if #order.errors.any? %>
<div class="error_messages">
<% for message in #order.errors.full_messages %>
* <%= message %> <br>
<% end %>
</div>
<% end %>
<p>
<%= f.label 'Select The Client' %><br />
<%= select :order, :client_id, Client.all().collect { |c| [ (c.firstname + " " + c.surname), c.id ] } %>
</p>
<%= f.fields_for :products do |pf| %>
<% #render 'product_fields', f: builder %>
<% end %>
<%= link_to_add_fields "Add Product", f, :products %>
<p class="button"><%= f.submit %></p>
<% end %>
<% flash.each do |name, msg| %>
<%= content_tag :div, "* " + msg, :id => "flash_#{name}" %><br />
<% end %>
<div id="copyright-notice"><div id="copyright_border">Copyright © Conner McCabe, all rights reserved.</div></div>
</div>
<% else %>
<script type="text/javascript">
window.location="<%= root_url %>"
</script>
<% end %>
Order Model:
class Order < ActiveRecord::Base
has_many :orderedproducts
has_many :products, through: :orderedproducts
has_one :client
attr_accessible :client_id, :order_total, :delivery_date, :products, :products_attributes
accepts_nested_attributes_for :products, :allow_destroy => true
before_save :generate_total
def generate_total
self.order_total = self.products.map(&:product_price).sum
end
end
Orders Controller:
class OrdersController < ApplicationController
def view
#orders = Order.all
end
def new
#order = Order.new
end
def create
#order = Order.new(params[:order])
if #order.save
redirect_to '/orders/view', :notice => "Order Created!"
else
render "new"
end
end
end
Product Fields Partial:
<fieldset>
<%= f.select :id, Product.all().collect {|p| [ p.product_name, p.id ] } %>
<%= f.hidden_field :_destroy %>
<%= link_to "remove", '#', class: "remove_fields" %>
</fieldset>
Products Model:
class Product < ActiveRecord::Base
#This line makes these elements accessible outside of the class.
attr_accessible :product_name, :product_price, :product_quantity, :product_supplier
has_many :orderedproducts
has_many :orders, through: :orderedproducts
#These attributes ensure that the data entered for each element is valid and present.
validates_presence_of :product_name
validates_presence_of :product_price
validates_numericality_of :product_price
validates_presence_of :product_quantity
validates_numericality_of :product_quantity
validates_presence_of :product_supplier
end
Application Helper:
module ApplicationHelper
def link_to_add_fields(name, f, association)
new_object = f.object.send(association).klass.new
id = new_object.object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
render(association.to_s.singularize + "_fields", f: builder)
end
link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
end
end
Ordered Products Model:
class Orderedproduct < ActiveRecord::Base
attr_accessible :order_id, :product_id, :quantity_ordered
belongs_to :order
belongs_to :product
end
I have listed every possible file that could contain an error, I know it's a bit excessive, but it's everything that is to do with it and better I include it than not at all.
I also followed this railscast guide: http://railscasts.com/episodes/196-nested-model-form-revised
To get to where I am, I edited it slightly so that it was suitable for my application.
Thanks in advance.
We had a similar issue on a project, except the relation was singular. The problem is that ActiveRecord is looking for an existing association; something like order.products.find(1). Since order is as new record this doesn't work.
You could create your own products_attributes= method and define the correct behaviour. But I think that you could just use nested attributes for the join model (Orderedproduct) instead of Product.
class Order
accepts_nested_attributes_for :orderedproducts
end
Then adjust the form fields appropriately. In the new form
f.fields_for :products do |pf| becomes f.fields_for :orderedproducts do |pf|
In the fields partial
<%= f.select :id, Product.all().collect {|p| [ p.product_name, p.id ] } %> becomes <%= f.select :product_id, Product.all().collect {|p| [ p.product_name, p.id ] } %>