I'm trying to set up price faceting on one of my models but I can't seem to get it to work properly. No matter which facet I select it only returns listings that's price equals $0. I'm not sure what I'm missing here. Any help would be much appreciated. Here's my code:
Migration
class CreateListings < ActiveRecord::Migration
def change
create_table :listings do |t|
t.references :member
t.text :title
t.text :link
t.text :category
t.text :description
t.decimal :price, :precision => 8, :scale => 2
t.timestamps
end
add_index :listings, :member_id
add_attachment :listings, :feature
end
end
Model
class Listing < ActiveRecord::Base
searchable :auto_index => true, :auto_remove => true do
text :title, :boost => 5
text :marker_list, :boost => 2
text :category
string :marker_list, :multiple => true, :stored => true
float :price
end
end
Controller
class ListingsController < ApplicationController
def index
#listings = Listing.order('created_at desc').page(params[:page]).per_page(60)
#search = Listing.search do
fulltext params[:search]
facet(:marker_list, :limit => 48, :sort => :count)
with(:marker_list, params[:tag]) if params[:tag].present?
facet(:price) do
row("$0 - $25") do
with(:price, 0.00..25.00)
end
row("$25 - $75") do
with(:price, 25.01..75.00)
end
row("$75 - $250") do
with(:price, 75.01..250.00)
end
row("$250+") do
with(:price).greater_than(250.00)
end
end
with(:price, params[:price]) if params[:price].present?
end
#query = params[:search]
#facet = params[:tag]
#price_facet = params[:price]
#results = #search.results
respond_to do |format|
format.html # index.html.erb
format.json { render json: #listings }
end
end
end
View
<% for row in #search.facet(:price).rows %>
<span class="eloc"><%= link_to row.value, :price => row.value %></span>
<% end %>
You might have already found a way around this, one of the workarounds i could find for this was to use the range facet instead of the query facet. SO it would be something like :
facet :price, :range => 0..300, :range_interval => 50
with(:price, Range.new(*params[:price].first.split("..").map(&:to_i))) if params[:price].present?
Hope it helps!
Related
I try to make a connection between a Match and 2 Players in a form where we can select the players from the list of the players registered:
<%= f.label :"Joueur 1" %>
<%= f.select :playerone, #players.collect {|a| [a.name, a.id]} , class: 'form-control' %>
<%= f.label :"Joueur 2" %>
<%= f.select :playertwo, #players.collect {|b| [b.name, b.id]} , class: 'form-control' %>
<%= f.label :Prolongations %>
<%= f.check_box :prolongations %><br />
<%= f.submit yield(:button_text), class: "btn btn-primary" %>
The schema of tables : with a Join Table Matches Players
create_table "matches", force: :cascade do |t|
t.boolean "prolongations"
end
create_table "matches_players", id: false, force: :cascade do |t|
t.integer "match_id", null: false
t.integer "player_id", null: false
t.index ["match_id", "player_id"], name: "index_matches_players_on_match_id_and_player_id"
t.index ["player_id", "match_id"], name: "index_matches_players_on_player_id_and_match_id"
end
create_table "players", force: :cascade do |t|
t.string "name"
t.integer "points"
end
In matches.controller :
class MatchesController < ApplicationController
attr_accessor :player_id, :playerone, :playertwo
def new
#match= Match.new
#players = Player.all
end
def create
#match = Match.new(match_params)
#players = Player.all
if #match.save
flash[:success] = "Votre match a bien été enregistré !"
redirect_to #match
else
render 'new'
p "Une erreur existe, veuillez recommencer."
end
end
def show
#match = Match.find(params[:id])
end
private
def match_params
params.require(:match).permit(:prolongations, :playerone, :playertwo)
end
end
And in the Match model :
class Match < ApplicationRecord
has_many :teams , class_name: "Team"
belongs_to :playerone, class_name: "Player" ,foreign_key: "player_id"
belongs_to :playertwo, class_name: "Player" ,foreign_key: "player_id"
end
And the result when I submit my form is :
Player(#69852298534200) expected, got "1" which is an instance of String(#4817000)
{"utf8"=>"✓",
"authenticity_token"=>".............",
"match"=>{"playerone"=>"1", "playertwo"=>"3", "prolongations"=>"0"},
"commit"=>"Enregistrer le match"}
How can I solve it ?
The easiest fix is just to use playerone_id and playertwo_id as the param keys (change the name of the inputs). If you use playerone the setter expects the argument to be an instance of Player - not a string containing an id.
Which will fix the immediate issue but there is a much better way to solve it.
Start by setting up a real many to many association:
class Match < ApplicationRecord
has_many :player_matches, dependent: :destroy
has_many :players, through: :player_matches
end
class Player < ApplicationRecord
has_many :player_matches, dependent: :destroy
has_many :matches, through: :player_matches
end
class PlayerMatches < ApplicationRecord
belongs_to :player
belongs_to :match
end
This lets you avoid a very awkward issue when you set two belongs to associations to the same table where the associated record can be in either column:
Match.find_by("(playerone_id = :a OR playertwo_id = :a) AND (playerone_id = :b OR playertwo_id = :b)", a: a, b: b)
Yeah thats how you have to query for a match between players. Joins can be even more messy.
With that setup you can simply assign players to a match by:
#match.player_ids = [1,2]
Which is exactly what you can do with the collection helpers:
<%= form_for(#match) do |f| %>
<div class="field">
<%= f.label :player_ids, "Select the players" %>
<%= f.collection_select :player_ids, Player.all, :id, :name, multiple: true %>
</div>
<% end %>
All you have to do on the controller side is whitelist player_ids:
class MatchesController < ApplicationController
# ...
def create
#match = Match.new(match_params)
# ...
end
def update
if #match.update(match_params)
# ...
else
# ...
end
end
# ...
private
def match_params
params.require(:match).permit(:foo, :bar, player_ids: [])
end
end
Hi guys i have a problem and i dont' know how to solve it, i'm really new on the ROR's world.
preamble : each municiplaty has many itinerary, so :
1) i've created the itinerary table with this migration :
class CreateItineraries < ActiveRecord::Migration
def change
create_table :itineraries do |t|
t.string :title
t.string :json
t.integer :muncipality_id
t.text :description
t.boolean :published, :default => true, :null => false
t.timestamps null: false
end
end
end
2) i've added the municipality_id reference to the itineraries table, with this migration :
class AddMunicipalityIdToItineraries < ActiveRecord::Migration
def change
add_reference :itineraries, :municipality, index: true, foreign_key: true
end
end
3) i've created another table for the translations of itineraries :
class AddTranslationTablesForItineraries < ActiveRecord::Migration
def up
Itinerary.create_translation_table!({
:title => :string
}, {
:migrate_data => true
})
end
def down
add_column :itineraries, :title, :string
Itinerary.drop_translation_table! :migrate_data => true
end
end
now, the problem is when i try to save the data from the relative simple_form, it save the itinerary's title only in the translations table, why?!
here the code of the simple_form :
<%= simple_form_for [:admin, #municipality, #itinerary], url: #url, :html => {:class => ''} do |f| %>
<%= render 'application/translation_form_heading' %>
# ...
<%= f.input :title, required: true %>
<%= f.input :description, label: 'description', :as => :ckeditor, :input_html => {ckeditor: {toolbar: get_toolbar('default')},:rows => 15} %>
<%= f.input :json, required: true, label: 'GeoJSON', as: :text, :input_html => {:rows => 15} %>
# ...
<button type="submit" class="btn btn-primary pull-right">Save itinerary</button>
<% end %>
maybe it's a newbie question, but i don'r really know how to solve it, thank you!
edit : here the code of the itinerariesController :
class Admin::ItinerariesController < InheritedResources::Base
layout 'admin'
before_filter :authenticate_admin!
before_filter :set_page_title
load_and_authorize_resource
actions :all, :except => [:show]
belongs_to :municipality
def index
#itineraries = Itinerary.ordered
end
def new
#url = admin_municipality_itineraries_path(params[:municipality_id])
new!
end
def edit
#url = admin_municipality_itinerary_path(params[:municipality_id], params[:id])
edit!
end
def update
unless params[:translate_to].blank?
I18n.with_locale(params[:translate_to]) {
update!
}
else
update!
end
end
def set_page_title
#page_title = PointOfInterest.model_name.human(:count => 2).titleize
end
def create
create! {
admin_municipality_itineraries_path
}
end
private
def permitted_params
params.permit(:itinerary => [:id, :title, :json,:description, :municipality_id] )
end
end
Try to update this one in controller
private
def permitted_params
params.permit(:itinerary => [:id, :title, :description, :municipality_id, :json] )
end
You need to permit JSON value in params always at the end
I am trying to pull up an edit page for my simple system.
Here's my controller for student look like:
class StudentsController < ApplicationController
def index
#students = Student.newest_first
end
def show
#student = Student.find(params[:student_id])
end
def new
#student = Student.new
end
def create
#student = Student.new(student_params_create)
if #student.save
flash[:notice] = "Student record created successfully"
redirect_to(students_path)
else
render('new')
end
end
def edit
#student = Student.find(params[:student_id])
end
def update
#student = Student.find(params[:student_id])
if #student.update_attributes(student_params_update)
flash[:notice] = "Students updated"
redirect_to(students_path)
else
render('edit')
end
end
def delete
#student = Student.find(params[:student_id])
end
def destroy
#student = Student.find(params[:student_id])
#student.destroy
end
private
def student_params_create
params.require(:student).permit(:first_name, :last_name, :birthday, :email, :subjects, :username, :password)
end
def student_params_update
params.require(:student).permit(:first_name, :last_name, :birthday, :email, :subjects)
end
end
And I am trying to here's my index page where I can click edit on my student.
<% #students.each do |student|%>
<%= student.first_name %>
<%= student.student_id %>
<%= link_to("Show", student_path(student), :class => 'action show') %>
<%= link_to("Edit", edit_student_path(student), :class => 'action edit') %>
<%= link_to("Delete", delete_student_path(student), :class => 'action delete') %>
<% end %>
For my form edit, I got the ff:
<h2>Update Subject</h2>
<%= form_for(#student) do |f| %>
<%= f.text_field(:first_name) %>
<%= f.datetime_select(:created_at, :order => [:month, :day, :year]) %><
<%= f.submit("Update Subject") %>
<% end %>
When I tried to go to my resource for students: http://localhost:3000/students/
And click on one of my students I got the ff: error:
Any idea what am I doing wrong????
EDIT:
I set the 'id' to false during migration.
def up
create_table :students, :id => false do |t|
t.integer "student_id",:primary_key => true
t.string "first_name", :limit => 25
t.string "last_name", :limit => 50
t.string "email", :default => ' ', :null => false
t.string "birthday"
t.string "subjects"
t.string "teachers"
t.string "username", :limit => 25
t.string "password_digest"
t.timestamps
end
reversible do |dir|
dir.up { execute "ALTER TABLE students AUTO_INCREMENT = 1000" }
end
# execute "CREATE SEQUENCE students_student_id_seq OWNED BY students.student_id INCREMENT BY 1 START WITH 1001"
end
def down
drop_table :students
# execute "DELETE SEQUENCE students_student_id_seq"
end
Routes:
resources :students do
member do
get :delete
end
end
UPDATE
You could need to update your routes.rb with
resources :students, param: :student_id
And your Student model with
self.primary_key = :student_id
NOTE that you're having the ActiveRecord::RecordNotFound exception because find method throws exception when it can't actually find the record needed. Try to use find_by_id method instead. It will just return nil in that situation. You'll be able to handle it easily and your app will not crash here. So you could edit your show action like this
def show
#student = Student.find_by_id(params[:student_id])
end
I am beginner in rails. I am building a forum application. It has a messaging facility where users can privately message(not real time. it is like a notification.) to other users. I already achived this. But I want to add blocking feature where user can block other users to avoid getting messages from those particular users. How can i do this? I appreciate your answers. Thanks in advance.
Here is my code.
Notifications Controller
class NotificationsController < ApplicationController
layout "posts"
after_action :read_message, only: [:index]
def index
#notifications = Notification.where(:recipient_id => session[:registered_id]).order("created_at DESC")
end
def new
#user = User.find(session[:user_id])
#notification = #user.notifications.new
end
def create
#user = User.find(session[:user_id])
#notification = #user.notifications.new notification_params
if #notification.save
redirect_to(:controller => "posts", :action => "index")
else
render "new"
end
end
def sent_messages
#notifications = Notification.where(:user_id => session[:user_id]).order("created_at DESC")
end
private
def notification_params
params.require(:notification).permit(:message, :user_id, :recipient_id, :status)
end
def read_message
#notifications = Notification.where(:recipient_id => session[:registered_id]).order("created_at DESC")
#notifications.read_all
end
end
Notification model
class Notification < ActiveRecord::Base
belongs_to :user
validates :message, :presence => true
validates :recipient_id, :presence => true
def self.read_all
Notification.all.update_all(status: true)
end
end
Notification migration
class CreateNotifications < ActiveRecord::Migration
def change
create_table :notifications do |t|
t.text :message
t.integer :user_id
t.string :recipient_id
t.boolean :read, default: false
t.references :user, index: true, foreign_key: true
t.timestamps null: false
end
end
end
** Notifications#index**
<div id = "messages_wrapper">
<% #notifications.each do |notification| %>
<div class="<%= notification.status ? 'message_wrapper_read' : 'message_wrapper_unread' %>">
<p><%= notification.message %></p>
<% if notification.user_id %>
<p class = "message_details">from <span><%= notification.user.registered_id %></span></p>
<% end %>
</div>
<% end %>
</div>
For the blocked users concept, you can add a custom attribute in user model called as blocked_users which is stored as an array in the db.
For postgresql you can use array datatypes.
In you notification.rb file,
#Validations,
validate :is_not_blocked_by_recipient
def is_not_blocked_by_recipient
#Check if the user is blocked or no, and write the logic
#self.errors.add()
end
It should work
I have a Rails 4.2 app which has 'Rooms', 'Bookings' and 'Extras'.
When making a booking it is for a room e.g. website.com/rooms/1/bookings/1
I have extras which I want to be associated with the booking for that room via check-boxes.
How can this be implemented? I've been reading about has_many :foo, :through => :bar associations but I'm not sure if that's the way to go.
The relevant code looks like this:
<!-- app\views\bookings\_form.html.erb -->
<%= form_for([#room, #booking]) do |f| %>
<p>
<%= f.label 'Select Customer:' %>
<%= f.collection_select :user_id, User.all, :id, :customer_name %>
</p>
<p>
<%= f.label 'start_time', 'Start Date and Time:' %>
<%= f.datetime_select :start_time, { minute_step: 15 } %>
</p>
<p>
<%= f.label 'length', 'Length of booking in hours:' %>
<%= f.number_field 'length', min: 1 %>
</p>
<p>
<%= f.label 'Room Price:' %>
<%= number_to_currency #room.price, unit: "£" %>
</p>
<p>
<%= f.label 'Extras:' %>
<%= f.collection_check_boxes :extra_ids, Extra.all, :id, :extra_info %>
</p>
<%= f.submit 'Submit' %>
<% end %>
# app\models\booking.rb
class Booking < ActiveRecord::Base
belongs_to :room
belongs_to :user
has_many :additions
has_many :extras, :through => :additions
end
# app\models\extra.rb
class Extra < ActiveRecord::Base
belongs_to :extracat
has_many :additions
has_many :bookings, :through => :additions
def extra_info
"#{name}"
end
end
# This model is for the has_many through testing I tried
# app\models\addition.rb
class Addition < ActiveRecord::Base
belongs_to :booking
belongs_to :extra
end
# Relevant section of schema
create_table "additions", force: :cascade do |t|
t.integer "booking_id"
t.integer "extra_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "bookings", force: :cascade do |t|
t.datetime "start_time"
t.datetime "end_time"
t.integer "length"
t.integer "room_id"
t.integer "user_id"
t.integer "extra_id"
end
EDIT - The section within the bookings show page.
# app\views\bookings\show.html.erb
<% #booking.extras.each do |e| %>
<%= e.name %>,
<% end %>
EDIT - Adding bookings controller
class BookingsController < ApplicationController
respond_to :html, :xml, :json
before_action :find_room
def index
#bookings = Booking.where("room_id = ? AND end_time >= ?", #room.id, Time.now).order(:start_time)
respond_with #bookings
end
def new
#booking = Booking.new(room_id: #room.id)
end
def create
#booking = Booking.new(params[:booking].permit(:room_id, :start_time, :length))
#booking.room = #room
if #booking.save
redirect_to room_bookings_path(#room, method: :get)
else
render 'new'
end
end
def show
#booking = Booking.find(params[:id])
end
def destroy
#booking = Booking.find(params[:id]).destroy
if #booking.destroy
flash[:notice] = "Booking: #{#booking.start_time.strftime('%e %b %Y %H:%M%p')} to #{#booking.end_time.strftime('%e %b %Y %H:%M%p')} deleted"
redirect_to room_bookings_path(#room)
else
render 'index'
end
end
def edit
#booking = Booking.find(params[:id])
end
def update
#booking = Booking.find(params[:id])
# #booking.room = #room
if #booking.update(params[:booking].permit(:room_id, :start_time, :length))
flash[:notice] = 'Your booking was updated succesfully'
if request.xhr?
render json: {status: :success}.to_json
else
redirect_to resource_bookings_path(#room)
end
else
render 'edit'
end
end
private
def save booking
if #booking.save
flash[:notice] = 'booking added'
redirect_to room_booking_path(#room, #booking)
else
render 'new'
end
end
def find_room
if params[:room_id]
#room = Room.find_by_id(params[:room_id])
end
end
def booking_params
params.require(:booking).permit(:user_id, :extra_id)
end
end
How is it possible to associate the extras with a booking? As so far they are not being saved with the booking into the database. Is this a controller issue?
You're not permitting the parameters correctly - the name is extra_ids. In addition since the parameter is an array you need to permit it like so:
params.require(:booking).permit(:room_id, :start_time, :length, :extra_ids => [])
Personally I recommend setting action controller to raise an error when unpermitted parameters are encountered in development or tests - very easy otherwise to miss the log messages