Accessing only some pieces of data from a rails model - ruby-on-rails

I have a userinfor model which has name, userinfo_id, user_id. I have a user model with user_id. I have a video model with video_id,name, userinfo_id and user_id. So If a user uploads a video, and his user_id is 5, and userinfo_id is 10, the video model info will be as follows: Video_id: some number, name: nameofvid, userinfo_id: 10, and user_id: 5. Now that the relationship is explained, I am displaying all the userinfo data and video on the index page. I have a small search bar in my index page too, so my controller index function looks like this:
My userinfos controller index function:
def index
#userinfors = Userinfo.where(["name LIKE ?","%#{params[:search]}%"])
#myvideo = Video.where(:user_id => #userinfors.user_id)
end
When I run this, I get the following error:
The line 6 they are referencing is the "#myvideo = ...." line in the index function.
My index view:
<%= form_tag userinfos_path, :method => 'get' do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "search" %>
<% end %>
<div>
<% #myvideo.each do |myvideo| %>
<div>
<%= video_tag myvideo.introvideo_url.to_s, :size => "240x160", :controls =>true %>
</div>
<div>
<% #userinfors.each do |userinfor| %>
<div>
<% if userinfor.user_id == myvideo.user_id %>
<p><span>Name: </span> <%= userinfor.name %> </p>
<p><span>College: </span> <%= userinfor.college %> </p>
<p><span>GPA: </span> <%= userinfor.gpa %> </p>
<p><span>Major: </span> <%= userinfor.major %> </p>
<%= link_to "profile", userinfo_path(myvideo.userinfo_id) %>
<% end %>
</div>
<% end %>
</div>
<% end %>
</div>
#userinfors gets all the records where the name of the record matches the name entered in the search bar. This part works. So let's assume there are 100 records. 10 of those are named THOMAS. Then when THOMAS is entered in the search bar, #userinfors will have 10 records in it, right? Because only 10 are named thomas. That means those 10 records have different individual user_id's. Then what I want to happen is, the program will go through the 100 video records, and if the user_id in that video record matches the user_id in one of the 10 #userinfors records, that video will be added to the #myvideo variable. So at the end, #myvideo will have 10 records. The user_id's of the ten records in #userinfors will be equal to the user_id's of the ten records in #myvideo. This is what I want to happen.
User model:
class User < ActiveRecord::Base
has_many :userinfos
has_many :videos
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Userinfo model:
class Userinfo < ActiveRecord::Base
belongs_to :user
has_many :videos, through: :user
def info_complete?
name? && email? && college? && gpa? && major?
end
end
Video model:
class Video < ActiveRecord::Base
belongs_to :user
mount_uploader :introvideo, VideoUploader
end

You're accessing to an ActiveRecordRelationship to get the user_id attribute, to do it you need to access to an specific object within that relationship.
You're using the result of a where statement that's an ActiveRecordRelationship to create another query passing that object. You should iterate over every element inside that relationship, but isn't an action to be performed within a controller.
You could create a helper, in app/helpers/userinfos_helper.rb which receives the user_id and returns all the video that have that user_id as value, maybe:
# app/helpers/userinfos_helper.rb
def video_by_user_id(user_id)
Video.where('user_id = ?', user_id)
end
Then in your view, you can get the user_id when you iterate over the #userinfors and pass it to your helper:
# app/views/userinfos/index.html.erb
<% #userinfors.each do |user| %>
<% video_by_user_id(user.user_id).each do |video| %>
<%= video.path %>
<% end %>
<% end %>

Related

How to associate user to news?

I want to link each news with some particular user.
I linked comments to particular news, but this doesn't work
_form.html.erb
<%= form_for([#user , #user.newss.build]) do |form| %>
<%# if news.errors.any? %>
<div id="error_explanation">
<h2><%#= pluralize(news.errors.count, "error") %> prohibited this
news from being saved:</h2>
<ul>
<%# news.errors.full_messages.each do |message| %>
<li><%#= message %></li>
<%# end %>
</ul>
</div>
<%# end %>
<div class="field">
<%= form.label :title %>
<%= form.text_field :title %>
</div>
<div class="field">
<%= form.label :description %>
<%= form.text_area :description %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
my user.rb
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :news
end
#my news.rb
class News < ApplicationRecord
has_many :comments
belongs_to :user
end
It shows different kind of errors I can't understand that...
I will recommend doing this at controller level, if you have a user logged in and you have a news controller initiate news object and create object like below,
class NewsController < ApplicationController
def new
#news = News.new #place this inside your form
end
def create
#news = current_user.news.create permit_params
if #news.errors.blank?
# Redirect or concerned logic here
else
# Rerender errors to the form
end
end
private
def permit_params
params.require(:news).permit(:title, :description)
end
end
This will make sure only the news is binded to the user who is creating it otherwise the for will be passing user_id that is an exposed vulnerability. Hope this helps :)
Ruby on rails follows the convention over configuration that means you just need to follow proper conventions to get proper result.
For Example:
Here News belongs to user and user has many news
so to fetch news of particular user you will do user.news and for news you will do news.user
Here we use the plural of news while the singular form of user
So in your code you just made a little convention mistake in your form for.
Just remove extra 's' from newss in your following code.
<%= form_for([#user , #user.newss.build]) do |form| %>
this has to be:
<%= form_for([#user , #user.news.build]) do |form| %>

How to add record to an array stored on my data base instead of updating an existing one on rails?

So i have a User model which has a column called debts, what i want is the possibility of adding multiple debts to each user, something like an array of debts stored in the debts column, right now what is happening is that when i add a new debt to the user, it overrides the existing debt instead of adding it as an array object.
THIS IS MY CONTROLLER.
class UsersController < ApplicationController
def index
#students = User.with_role :student
#teachers = User.with_role :teacher
end
def show
#user = User.find(params[:id])
if request.patch?
#user.update(user_params)
end
end
private
def user_params
params.require(:user).permit(:debts)
end
end
THIS IS MY VIEW
<div class="container">
<div class="row">
<div class="col-sm-12">
<% if current_user %>
<% if current_user.username == #user.username %>
<h1><%= #user.username %>, logueado como usuario</h1>
<% elsif current_user.has_role? :admin%>
<h1><%= #user.username %>, logueado como admin</h1>
<%= form_for #user do |f| %>
<div class="form-group">
<%= f.text_field :debts, class: "form-control input-lg", placeholder: "Selecciona mes y año", id: "datepicker"%>
</div>
<div class="form-group">
<%= f.submit class: "btn btn-primary btn-lg btn-block" %>
</div>
<% end %>
<% end %>
<% end %>
</div>
</div>
</div>
THIS IS MY MODEL
class User < ActiveRecord::Base
rolify
after_create :assign_role
serialize :debts
def assign_role
if self.username == "admin"
self.add_role(:admin) if self.roles.blank?
elsif self.role == "student"
self.add_role(:student) if self.roles.blank?
elsif self.role == "teacher"
self.add_role(:teacher) if self.roles.blank?
end
end
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable
end
As a general approach to this, I would recommend to store the debts in a separate model which you can associate with the User model in a :has_many relationship.
But to answer the actual question, you could solve it by using a dedicated variable on the User model which holds the value that you want to add to the debts, and then manually add it to the array, for example:
class User < ActiveRecord::Base
# ... existing code
# Prepares an attribute that is not represented by a column in
# the database table, but can still be used in the forms
attr_accessor :add_debt
# Performs a callback on save to check if any debts should be added
# and if there is, it appends to the existing array instead of replacing
before_save do
if #add_debt.present?
self.debts << #add_debt
end
end
end
And in the views, you simple replace the attribute for the textfield like this:
<%= f.text_field :add_debt %>

Using includes to join two models in Rails and using the search results

Im a real noob at Rails. Im actually a Business Analyst trying to teach myself code so i can work with Devs a lot closer at work. I am having issues with retrieving fields from models.
I have two modals User and CricketClub Adverts, these can be seen below:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
mount_uploader :picture, PictureUploader
#validates_presence_of :picture
#validates_integrity_of :picture
#validates_processing_of :picture
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :cricket_club_advert
has_many :application
end
and
class CricketClubAdvert < ActiveRecord::Base
belongs_to :user, foreign_key: "user_id"
has_many :application
mount_uploader :picture, PictureUploader
end
In my controller I have the following code:
#adverts = User.includes(:cricket_club_advert)
In my view i have the following:
<% #adverts.each do |advert| %>
<!-- Feed Entry -->
<div class="row">
<div class="large-2 columns small-3">
<%= image_tag(advert.picture_url) %>
</div>
<div class="large-10 columns">
<h4> <%= link_to advert.cricket_club_advert.title, cricket_club_advert_path(advert.cricket_club_advert.id) %></h4>
<%= truncate(strip_tags(advert.cricket_club_advert.description), length: 250) %>
<ul class="inline-list">
<li>More</li>
</ul>
</div>
</div>
<hr>
<!-- End Feed Entry -->
<% end %>
According to the documentation I have used the calls right, but i get this error:
undefined method `title' forCricketClubAdvert::ActiveRecord_Associations_CollectionProxy:0x007feca33270c0>
I cant figure out what i am doing wrong.
What you really do here is you're iterating over users and its adverts. So your variable name is quite misleading, it should be:
#users = User.includes(:cricket_club_adverts)
and in your view:
<% #users.each do |user| %>
# ...
# ... here the iteration over adverts starts:
<% user.cricket_club_adverts.each do |advert| %>
# ...
<% end %>
# ...
<% end %>
BTW note the plural form - if you use has_many association, you should name your assiciations in plural.
Instead of :
#adverts = User.includes(:cricket_club_advert)
Use :
#adverts = User.includes(:cricket_club_adverts)
Because, one user has got many cricket_club_adverts (has - many relation)
first_advert = #adverts.first
cricket_advert = first_advert.cricket_club_adverts.first
#as one user can have many cricket_club_adverts and each
#cricket_club_advert will have title, id, description attributes.
hence title, id, description can be fetched by:
cricket_advert.title #fetch the title
cricket_advert.id #fetch the id
cricket_advert.description # fetch the description.

ActionView::Template::Error (undefined method `stage' for #<User:0x007f80045ca0e0>)

I'm having an error with a form in a view, can't get it why is happening. I keep getting ActionView::Template::Error (undefined method 'stage' for #<User:0x007f80045ca0e0>)
I have two models, User and Stage. User has_many stages, and stages belongs_to to user. It's as follows
The Stage Model:
class Stage < ActiveRecord::Base
belongs_to :user
end
The User Model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_one :user_setting
has_many :matches, dependent: :destroy
has_many :stages, dependent: :destroy
end
and in the user controller I have as follows:
class UsersController < ApplicationController
def show
#newMatch = current_user.matches.new
#newStage = current_user.drivepipes.new
end
end
and a form on the show.html.erb
<%= form_for [current_user], url: user_stages_path(current_user, #newStage) do |s| %>
<%= s.text_field :stage, placeholder: "Stage" %>
<%= s.submit "Save" %>
<% end %>
If each user has many stages and you're making a form for your user, <%= s.text_field :stage, placeholder: "Stage" %> is going to give you an error because the user has_many :stages which is an enumerable. So you're going to want something like
<%= form_for [current_user], url: user_stages_path(current_user, #newStage) do |s| %>
<% current_user.stages.each do |stage| %>
<%= s.text_field stage, placeholder: "Stage" %>
<% end %>
<%= s.submit "Save" %>
<% end %>
Assuming you want a text field for every stage the user has, that is. Perhaps that's not the goal here?
There is one-to-many relationship between User and Stage. So, foreign key will reside in Stage table i.e. user_id. You should make clear that You can't have an attribute 'stage' or stage_id in User object if it has many stages. However Rails have helpers:
#user.stages
will return array of stages which have been saved with this user's id, using query:
select * from stages where stages.user_id = #user.id
While:
#user.stage
will raise error.
If you want to get input for newly created stage object associated with current user, You view code should look like this:
<%= form_for current_user, url: user_stages_path(current_user, #newStage) do |user_form| %>
<%= user_form.fields_for #newStage do |stage| %>
<%= stage.text_field :stage, placeholder: "Stage" %>
<% end %>
<%= user_form.submit "Save" %>
<% end %>
Later, in controller; you can get the stage object in the similar way:
stage = Stage.new params[:user][:stage]

"is not included in the list" when fields_for on a one-to-many

This is on rails 2.3. I cut a bunch of code out to hopefully get to the point of the problem. When I click save on a User object with 1 or more EmailPreferences, I get
1 error prohibited this user from being saved
There were problems with the following fields:
Notification type is not included in the list
class User < ActiveRecord::Base
has_many :email_preferences
accepts_nested_attributes_for :email_preferences
attr_accessible :email_preferences_attributes
end
class EmailPreference < ActiveRecord::Base
# receives is a boolean, notification_type is a string.
attr_accessible :user_id, :receives, :notification_type
belongs_to :user
end
class UsersController < ApplicationController
def new
#user = User.new
#user.email_preferences.build :receives=>false, :notification_type=>"outage"
end
def edit
#user = User.find(params[:id])
end
end
# app/views/user/_form.rhtml
<% form_for :user, user do |f| -%>
<% f.fields_for :email_preferences do |preference_form| -%>
<dd>
<%= preference_form.check_box :receives %>
<!-- I just want to display the notification type. I do not want to edit it. -->
<%= preference_form.object.notification_type %>
</dd>
<% end -%>
<%= form_submit f.object, :cancel => companies_path %>
<% end -%>
Edit
Even better, how would you go about debugging error messages that aren't so helpful?
Alright, adding a hidden input does seem to work. It also looks like Rails doesn't need the hidden notification_type if the email preference is already in the database. So perhaps the rule is that for new sub-objects, you need to include all the required fields.
<% f.fields_for :email_preferences do |preference_form| -%>
<dd>
<%= preference_form.check_box :receives %>
<!-- I just want to display the notification type. I do not want to edit it. -->
<%= preference_form.object.name %>
<%= preference_form.hidden_field :notification_type %>
</dd>
<% end -%>

Resources