Rails 4 - using 'where' to search & display certain users - ruby-on-rails-4

I'm a little stuck and any help or advise would be much appreciated.
I would like to display only users that have a resume but I am unsure how
- I have the below codings in my file - your advise & help will be much appreciated.
in my user/index.html
<% users.each do |user| %>
<%= user.resume.summary %>
<% end %>
schema
create_table "resumes", force: true do |t|
t.text "summary"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
models
user.rb
has_one :resume
resume.rb
belongs_to :user
I would like to do a search that only displays users with a resume.
I tried the below but no luck
<% users.where(resume_id: !nil).each do |user| %>
<%= user.resume.summary %>
<% end %>
<% users.where("resume IS NOT NULL != ?", "").each do |user| %>
<%= user.resume.summary %>
<% end %>
I tried writing as a scope but no luck
user.rb file
scope :users_with_resumes, -> {where(['resume != ?', nil])}
users/index.html.erb file
<% #users.users_with_resumes.each do |userj| %>
<%= user.resume.summary %>
<% end %>

You're close to hitting the mark, but your syntax in your attempts is slightly off:
# This won't work because you're now searching for the value !nil (or 'true')
<% users.where(resume_id: !nil).each do |user| %>
<%= user.resume.summary %>
<% end %>
# This is a double negative, syntactically incorrect, and referencing resume instead of resume_id
<% users.where("resume IS NOT NULL != ?", "").each do |user| %>
<%= user.resume.summary %>
<% end %>
You should instead use one of the following:
users.where.not(resume_id: nil)
users.where("resume_id IS NOT NULL")
I think you'll find either of those statements will serve your purpose whether scoped or otherwise.

The below code displays only users with resumes
Association
user has_one resume
resume belongs_to user
schema
create_table "resumes", force: true do |t|
t.text "summary"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
user.rb
scope :users_with_resumes, -> {where("id in (select user_id from resumes)")}
or instead of a scope you can write a method
def self.users_with_resumes
where("id in (select user_id from resumes)")
end
users/index.html.erb [this display only users with a resume]
<% #users.users_with_resumes.each do |user| %>
<%= user.resume.summary %>
<% end %>

Related

Nested attributes fail in rails 5, but works in rails 4

I have an exercise called "BillApp" basically it's a Bill that have some products, and i should could make bills, calculate IVA, etc.
I have the next schema:
create_table "bill_items", force: :cascade do |t|
t.integer "amount"
t.integer "product_id"
t.integer "bill_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["bill_id"], name: "index_bill_items_on_bill_id"
t.index ["product_id"], name: "index_bill_items_on_product_id"
end
create_table "bills", force: :cascade do |t|
t.string "user_name"
t.string "dni"
t.date "expiration"
t.float "sub_total"
t.float "grand_total"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "products", force: :cascade do |t|
t.string "name"
t.string "description"
t.float "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Bill model:
class Bill < ApplicationRecord
has_many :bill_items
has_many :products, through: :bill_items
accepts_nested_attributes_for :bill_items
end
BillItem model:
class BillItem < ApplicationRecord
belongs_to :product
belongs_to :bill
end
Product model:
class Product < ApplicationRecord
has_many :bill_items
has_many :bills, through: :bill_items
end
The ProductsController is a normal one, generated by scaffold, it doesn't matter.
BillsController:
class BillsController < ApplicationController
before_action :set_bill, only: [:show, :update, :destroy, :edit]
def new
#bill = Bill.new
#bill.bill_items.build
end
def create
#bill = Bill.new(bill_params)
byebug
#bill.save
end
private
def set_bill
#bill = Bill.find(params[:id])
end
def bill_params
params.require(:bill).permit(:user_name, :dni, { bill_items_attributes: [:product_id, :amount, :bill_id] })
end
end
And finally the Bill new view:
<%= form_for(#bill) do |f| %>
<div>
<%= f.label :user_name %>
<%= f.text_field :user_name %>
</div>
<div>
<%= f.label :dni %>
<%= f.text_field :dni %>
</div>
<%= f.fields_for :bill_items do |fp| %>
<div>
<%= fp.label :product %>
<%= fp.collection_select :product_id, Product.all, :id, :name %>
</div>
<div>
<%= fp.label :amount %>
<%= fp.number_field :amount %>
</div>
<% end %>
<%= f.submit %></div>
<% end %>
The problem is very specific, in rails 5 when it try to call #bill.save it fails and in the errors it shows:
#<ActiveModel::Errors:0x007fd9ea61ed58 #base=#<Bill id: nil, user_name: "asd", dni: "asd", expiration: nil, sub_total: nil, grand_total: nil, created_at: nil, updated_at: nil>, #messages={:"bill_items.bill"=>["must exist"]}, #details={"bill_items.bill"=>[{:error=>:blank}]}>
But it works perfectly in Rails 4.2.6.
The entire project folder is here: https://github.com/TheSwash/bill_app
currentrly in the branch feature/bills_controller
Somebody have an idea about what's happening?
the problem it's the bill_items validation
In rails 5 the belongs_to association required by default
http://blog.bigbinary.com/2016/02/15/rails-5-makes-belong-to-association-required-by-default.html

Ruby on Rails 4: Searchkick displaying all items instead of searched results

I have a Forum that has_many :forum_threads and has_many :forum_posts, through: :forum_threads. So basically my Forums have their own Forum Threads that are related to that particular Forum topic. I've added Searchkick to handle the search form. Searchkick is working for my Forum table but not for my ForumThread table.
There is no error, it just renders out all of the forum threads instead of rendering the query that the form was given.
Searchkick GitHub
Here are my files:
forum.rb
class Forum < ActiveRecord::Base
accepts_nested_attributes_for :forum_threads
has_many :forum_posts, through: :forum_threads
accepts_nested_attributes_for :forum_posts
searchkick text_start: [:title], suggest: [:title], autocomplete: [:title]
def search_data
{
title: title
}
end
end
forums_controller.rb
class ForumsController < ApplicationController
def index
query = params[:q] || "*"
#forums = Forum.search(query, suggest: true, fields: [:title],
boost_where: {specific: :exact})
end
end
views/forums/index.html.erb
<%= form_tag forums_path, method: :get do |f| %>
<%= text_field_tag :q, nil, class: 'form-control', placeholder: 'Search...' %>
<% end %>
<% if #forums.suggestions.any? %>
<p class="lead">
<em>Did you mean: <strong><%= #forums.suggestions.first %></strong>?</em>
</p>
<% end %>
forum_thread.rb
class ForumThread < ActiveRecord::Base
belongs_to :user, counter_cache: true
belongs_to :forum, counter_cache: true, touch: true
has_many :forum_posts, dependent: :destroy
accepts_nested_attributes_for :forum_posts
validates :subject, presence: true
validates_associated :forum_posts
searchkick text_start: [:subject], suggest: [:subject], autocomplete: [:subject]
def search_data
{
subject: subject,
description: description
}
end
end
forum_threads_controller.rb
class ForumsController < ApplicationController
def index
query = params[:q].presence || "*"
#forum_threads = #forum.forum_threads.search(query, suggest: true, fields: [:subject, :description])
end
end
views/forum_threads/index.html.erb
<%= form_tag forum_forum_threads_path(<!-- something here? -->), method: :get do %>
<%= text_field_tag :q, nil, class: 'form-control', placeholder: 'Search...' %>
<% end %>
<% if #forum_threads.suggestions.any? %>
<p class="lead"><em>Did you mean: <%= #forum_threads.suggestions.first %>?</em></p>
<% end %>
routes.rb
Rails.application.routes.draw do
resources :forums do
resources :forum_threads do
resources :forum_posts do
member do
put 'like', to: 'forum_posts#upvote'
put 'dislike', to: 'forum_posts#downvote'
end
end
end
end
end
I just made a variable for suggestions to use in the view.
forum_threads_controller.rb
def index
query = params[:q].presence || "*"
#forum_threads = ForumThread.search(query,
where: { forum_id: #forum.id },
fields: [:subject, :description],
boost_where: {specific: :exact}, suggest: true, highlight: true)
#forum_threads_suggestions = []
if #forum_threads.empty? && #forum_threads.suggestions.any?
#forum_threads_suggestions = ForumThread.search(#forum_threads.suggestions.first, fields: [:subject], suggest: true,
boost_where: {specific: :exact}, highlight: true)
end
end
index.html.erb
<%= form_tag forum_forum_threads_path, method: :get do %>
<%= text_field_tag :q, nil, class: 'form-control', placeholder: 'Search...' %>
<% end %>
<% if #forum_threads.suggestions.any? %>
<p class="lead">
<em>
Did you mean: <strong><%= #forum_threads.suggestions.first %></strong>?
</em>
</p>
<% end %>
</div>
<!-- END SEARCH FORM -->
<!-- SHOW RESULTS AND SUGGESTIONS -->
<p class="light-grey"><em>
<%= pluralize #forum_threads.results.size, 'match' if params[:q].present? %>
<%= pluralize #forum_threads.suggestions.size, 'suggestion' if #forum_threads.suggestions.any? %>
</em></p>
<!-- END RESULTS AND SUGGESTIONS -->
<!-- SHOW FORUM THREADS -->
<% (#forum_threads.presence || #forum_threads_suggestions).each do |forum_thread| %>
I wrote an or statement to either show all forum_threads or suggestions.
forum_thread.rb)
searchkick fields: [:subject], suggest: ['subject'], highlight: [:subject]
def search_data
{
forum_id: forum.id,
forum_thread: #forum_thread,
subject: subject
}
end
I did the same thing for the forum model. I'm not sure if this is the best way to go about doing this so if someone else has something then please feel free to contribute.

Not sure why the VIEW does't work: Rails 4 nested attributes and has_many :through associaton in a form

I followed this page to build my app:
Rails 4 nested attributes and has_many :through associaton in a form
but it shows NOTHING in my VIEW:
(the weird thing is when i typed "f.fields_for :questionnaire_surveRys do |ff|" instead of the right one, it showed me the ocrrect page.
any suggestions will be greatly appreciated.
here are my Models:
questionnaire.rb
class Questionnaire < ActiveRecord::Base
has_many :questionnaire_surveys
has_many :surveys, through: :questionnaire_surveys
accepts_nested_attributes_for :questionnaire_surveys
end
questionnaire_survey.rb
class QuestionnaireSurvey < ActiveRecord::Base
belongs_to :questionnaire
belongs_to :survey
accepts_nested_attributes_for :survey
end
survey.rb
class Survey < ActiveRecord::Base
has_many :questions, :dependent => :destroy
accepts_nested_attributes_for :questions, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
has_many :questionnaire_surveys
has_many :questionnaires, through: :questionnaire_surveys
end
and this is my questionnaire_controller.rb
def new
#questionnaire = Questionnaire.new
#surveys = Survey.all
end
def questionnaire_params
params.require(:questionnaire).permit(:name, questionnaire_surveys_attributes: [:id, survey_attributes:[:id]])
end
this is my _form.html.erb
<%= form_for(#questionnaire) do |f| %>
<p>
<%= f.label :name %><br/>
<%= f.text_field :name %>
<div class="field">
<%= f.fields_for :questionnaire_surveys do |ff| %>
<%= ff.fields_for :survey do |builder| %>
<% #surveys.each do |survey| %>
<%= builder.check_box :id, {}, survey.id %>
<%= builder.label survey.name %>
<% end %>
<% end %>
<% end %>
</div>
</p>
<div class="actions">
<%= f.submit %>
</div>
UPDATED:
Started POST "/questionnaires" for ::1 at 2015-07-29 22:45:16 +0800
Processing by QuestionnairesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"k4SkRC08PwAHAo1iERmQCkssdQZYgf+uHwofPdeLbXo0O4/psY3Y7i/krQA01omToQ4VLlt/YQDNkcbpLGp86w==", "questionnaire"=>{"name"=>"what just happened", "questionnaire_surveys_attributes"=>{"0"=>{"survey_attributes"=>{"name"=>""}}}}, "commit"=>"Create Questionnaire"}
Unpermitted parameter: name
(0.1ms) begin transaction
SQL (0.7ms) INSERT INTO "questionnaires" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "what just happened"], ["created_at", "2015-07-29 14:45:16.374246"], ["updated_at", "2015-07-29 14:45:16.374246"]]
SQL (0.2ms) INSERT INTO "surveys" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2015-07-29 14:45:16.377439"], ["updated_at", "2015-07-29 14:45:16.377439"]]
SQL (0.1ms) INSERT INTO "questionnaire_surveys" ("questionnaire_id", "survey_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["questionnaire_id", "52"], ["survey_id", "38"], ["created_at", "2015-07-29 14:45:16.378845"], ["updated_at", "2015-07-29 14:45:16.378845"]]
(0.9ms) commit transaction
Redirected to http://localhost:3000/questionnaires/52
Completed 302 Found in 12ms (ActiveRecord: 2.0ms)
UPDATE - 2015/7/31
Started POST "/questionnaires" for ::1 at 2015-07-31 17:46:50 +0800
Processing by QuestionnairesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"t/00prIClAUVdqPFxOnkTaxRPhTdY082PAvHb/VQSO4QQh8LLrNz6z2Qg6fhJv3URnNePN6d0ZjukB67DrFZfw==", "questionnaire"=>{"name"=>"OMG", "questionnaire_surveys_attributes"=>{"0"=>{"survey_attributes"=>{"name"=>""}}}}, "commit"=>"Create Questionnaire"}
(0.2ms) begin transaction
SQL (0.7ms) INSERT INTO "questionnaires" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "OMG"], ["created_at", "2015-07-31 09:46:50.440466"], ["updated_at", "2015-07-31 09:46:50.440466"]]
SQL (0.4ms) INSERT INTO "surveys" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", ""], ["created_at", "2015-07-31 09:46:50.446176"], ["updated_at", "2015-07-31 09:46:50.446176"]]
SQL (0.2ms) INSERT INTO "questionnaire_surveys" ("questionnaire_id", "survey_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["questionnaire_id", "53"], ["survey_id", "39"], ["created_at", "2015-07-31 09:46:50.450001"], ["updated_at", "2015-07-31 09:46:50.450001"]]
(0.9ms) commit transaction
Redirected to http://localhost:3000/questionnaires/53
Completed 302 Found in 22ms (ActiveRecord: 2.4ms)
UPDATE - 2015/8/05
I can't upload pics here, hope this is what you need:
<input placeholder="vision" type="text" name="questionnaire[questionnaire_surveys_attributes][0][survey_attributes][name]" id="questionnaire_questionnaire_surveys_attributes_0_survey_attributes_name">
UPDATE - 2015/8/11
_form.erb.html
<div class="field">
<% #surveys.each do |survey| %>
<%= check_box_tag "questionnaire[questionnaire_surveys_attributes][][survey_id]", survey.id %>
<%= label_tag survey.name %>
<% end %>
</div>
questionnaires_controller.rb
params.require(:questionnaire).permit(:name, questionnaire_surveys_attributes: [:survey_id])
def new
#questionnaire = Questionnaire.new
#surveys = Survey.all
end
UPDATE - 2015/8/17
I misused the has_many :through and accepts_nested_attributes_for.
In has_many:xxx :through case, there is xxx_ids.
In accepts_nested_attributes_for xxx case, there is xxx_attributes.
I used accepts_nested_attributes_for in both questionnaire.rband questionnaire_survey.rb , which is a mistake.
The correct way to do what I want is use the has_many :through only.
Then my questionnaire_controller.rb will have
def questionnaire_params
params.require(:questionnaire).permit(:name, :survey_id=>[])
end
in _form view, it should be
<%= check_box_tag "questionnaire[survey_id][]", survey.id %>
it's much easier now.
#Rich Peck thanks for all your help.
First things first - if you're not seeing the form elements appear, it's because you've not got it set up correctly in the backend.
For the longest time, I tried to set this up and was getting very frustrated that the embedded form would not appear. It wasn't until I sorted it out properly that it worked. It's called graceful degradation (I think) - whereby no error will appear, yet functionality will be impaired.
Firstly, I think you haven't built your associated objects in the controller:
#app/controllers/questionnaire_controller.rb
def new
#questionnaire = Questionnaire.new
# You need to build the associated objects, like this:
#questionnaire.questionnaire_surveys.build.build_survey
#surveys = Survey.all
end
--
Secondly, there is a better way to show checkboxes for your #surveys object:
<%= ff.fields_for :survey do |survey| %>
<%= survey.collection_check_boxes :survey_ids, #surveys, :id, :name %>
<% end %>
You can read up about collection_check_boxes here
--
Thirdly, you should definitely learn haml. You could write your entire form like this:
= form_for #questionnaire do |f|
.name
= f.label :name
= f.text_field :name
.field
= f.fields_for :questionnaire_surveys do |ff| %>
= ff.fields_for :survey do |survey| %>
= survey.collection_check_boxes :survey_ids, #surveys, :id, :name
.actions
= f.submit
--
Finally, don't use HTML elements as styling.
<p> & <br> should only be used as markup. If you're using them for styling effect, you'll end up causing problems with browser compatibility etc.
You need to let your CSS do the styling (colouring, size, position), and any on-page elements used as ways to separate the content of your application.
Update
Okay, so I've looked at your BitBucket:
You need to uncomment #questionnaire.questionnaire_surveys.build.build_survey in app/controllers/questionnaires_controller.rb#20
If you do that, it should work.
I cannot see any problems with the construct of the models and controllers. Are you sure you've refreshed etc?
I see you're calling <%= render "form" %> - try putting the form directly in the new view to test if it will work.
Also, have you tried using a simple way to add the extra fields, like this:
<%= f.fields_for :questionnaire_surveys do |ff| %>
<%= ff.fields_for :survey do |builder| %>
<% #surveys.each do |survey| %>
<%= builder.text_field :name, placeholder: survey.name %>
<% end %>
<% end %>
Finally, if you post your posted parameters after form submit, I'll be in a much stronger position to see any of the errors/problems you may have.
--
You can change your params to the following:
#app/controllers/questionnaires_controller.rb
...
def questionnaire_params
params.require(:questionnaire).permit(:name, questionnaire_surveys_attributes: [:id, survey_attributes:[:name]])
end

Unexpected NoMethodError after migration to add new column

I have a player model inheriting from a user model to share authentication logic (devise) with a 3rd model (coach that also inherits from user).
class User < ActiveRecord::Base
end
class Player < User
end
class Coach < User
end
I'm trying to add a field to the player table when players register so I created a migration
rails g migration AddClubCoachEmailToPlayer club_coach_email:string
then ran the migration
rake db:migrate
for the file
class AddClubCoachEmailToPlayer < ActiveRecord::Migration
def change
add_column :players, :club_coach_email, :string
end
end
Schema as expected
create_table "players", force: true do |t|
t.datetime "created_at"
t.datetime "updated_at"
t.string "club_coach_email"
end
Now, I need to add the field to /views/players/registrations/new
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
#...
<div><%= f.label :position %><br />
<%= f.radio_button(:position, "Striker") %> Striker
<%= f.radio_button(:position, "Midfielder") %> Midefielder
<%= f.radio_button(:position, "Defender") %> Defender
</div>
<div><%= f.label :club_coach_email %><br />
<%= f.email_field :club_coach_email %></div>
<div><%= f.label :profile_name %><br />
<%= f.text_field :profile_name %></div>
#...
and I sanitize params through this technique from devise wiki; in lib/player_sanitizer.rb I add the new field.
class PlayerParameterSanitizer < Devise::ParameterSanitizer
private
def sign_up
default_params.permit(:first_name, :last_name, :profile_name, :password, :password_confirmation, :email, :grad_year, :position, :club_team, :formation, :club_coach_email)
end
def account_update
default_params.permit(:first_name, :last_name, :profile_name, :password, :password_confirmation, :email, :grad_year, :position, :club_team, :formation)
end
end
This is what my application controller looks like
class ApplicationController < ActionController::Base
def after_sign_in_path_for(user)
dashboard_path
end
protected
def devise_parameter_sanitizer
if resource_class == Player
PlayerParameterSanitizer.new(Player, :player, params)
elsif resource_class == Coach
CoachParameterSanitizer.new(Coach, :coach, params)
else
super
end
end
end
However, I must be missing some step because when I navigate to /players/sign_up I'm getting a NoMethodError in Players::Registrations#new
undefined method `club_coach_email' for #<Player:0x00000109296be8>
Obvioulsy, here is where the trace is pointing
<%= f.radio_button(:position, "Defender") %> Defender
</div>
<div><%= f.label :club_coach_email %><br />
<%= f.email_field :club_coach_email %></div>
<div><%= f.label :profile_name %><br />
<%= f.text_field :profile_name %></div>
What do I seem to not understand here?
As for me you're doing it too complex. From the information you gave there is no different functionality between this three different users types, therefore it will be easier to make all of them not through inheritance but with the devise roles.
In this way you'll have One user model with three different roles (User, Player, Coach).
Or there is other way - using different models in "devise way":
rails g devise User + rails g devise Player + rails g devise Coach
After this you'll get three almost separate models each with all devise functionality and methods (for example: player_signed_in?, current_coach, authenticate_player! etc.).

Strong params in Rails 4 (ArgumentError)

Situation
I want to create new Category using form.
In new.html.erb everything is good:
<%= form_for #cat do |f| %>
<%= f.label :description %>
<%= f.text_field :description %>
<br>
<%= f.label :position %>
<%= f.text_field :position %>
<%= f.submit %>
<% end %>
But after "Submit" is pressed ArgumentError in CategoriesController#create is raised (Unknown key: description). http://prntscr.com/1fijdk
categories_controller.rb
class CategoriesController < ApplicationController
def index
#categories = Category.all
end
def new
#cat = Category.new
end
def create
#category = Category.find(params[:category])
redirect_to :categories
end
end
category.rb
class Category < ActiveRecord::Base
has_many :items
end
schema.rb
ActiveRecord::Schema.define(version: 20130715035836) do
create_table "categories", force: true do |t|
t.string "description"
t.integer "position"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "items", force: true do |t|
t.string "name"
t.float "price"
t.text "description"
t.integer "category_id"
t.datetime "created_at"
t.datetime "updated_at"
end
end
In Rails 3 everything works great, but in Rails 4 attr_accessible is not generated and I'm a little bit confused. Where is a problem?
Rails 4 does not use attr_accessible but strong_parameters to allow (or not) mass assignment.
Now this is handled by the controller and not by the model, you have to specify in your controller what are the permitted attributes...
See : http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters to understand how it works and at https://github.com/rails/strong_parameters
Cheers