How to display which user created the post? - ruby-on-rails

Trying to learn ruby on rails by creating a reddit clone.
So now I'm trying display the username of the user who created the post, but I'm only getting it displayed as u/username everywhere.
Also when I try to click on u/username to see if I can get data about user by going to his page, all I'm getting is an error saying:
undefined method `username' for nil:NilClass
This is my partial _list class that displays data about post:
<% posts.each do |post| %>
<%= link_to post.community.name %> | Posted by <%= link_to post.account.username, profile_path(:username) %> <%= time_ago_in_words post.created_at%> ago. </p> </small>
<%= link_to post.title, community_post_path(post.community_id, post) %>
<%= truncate post.body, length: 200 %>
<% end %>
profile.html.erb just to display username for now:
<%= #profile.username %>
account.rb:
class Account < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :posts
has_many :communities
validates_presence_of :username
end
public_controller:
class PublicController < ApplicationController
def index
#communities = Community.all.limit(5)
#posts = Post.order(id: :desc).limit(20)
end
def profile
#profile = Account.find_by_username params[:username]
end
end
post.rb:
class Post < ApplicationRecord
belongs_to :account
belongs_to :community
validates_presence_of :title, :body, :account_id, :community_id
end
and routes.rb:
Rails.application.routes.draw do
devise_for :accounts
get "u/:username" => "public#profile", as: :profile
resources :communities do
resources :posts
end
root to: "public#index"
end
Full repo here

Related

Ruby on Rails Search Bar for Devise Users

hey guys im working on an application where there a two devise users 'Family' & 'Team', I want one of the users to be able to search for the other users by name. I'm having trouble doing this i currently have the following code
team.rb
class Team < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :confirmable
def self.search(user_name)
if user_name
user_name.downcase!
where('LOWER(name) LIKE ?', "%#{user_name}%")
else
all
end
end
end
routes.rb
devise_for :teams, path: 'teams' , controllers: { sessions: "teams/sessions", confirmations: 'teams/confirmations', registrations: 'teams/registrations'}
controller.rb
def team_search
#users = Team.search(params[:search])
end
view
<%= form_tag teams_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
You can use a separate controller and path:
class TeamsController
def search
# ...
end
end
# routes.rb
resources :team do
collection do
get :search
end
end

Rails 5: Displaying form from Joined table

This is my first foray into joined tables and Many-to-Many relationships and I am relatively new to Ruby/Rails as well.
This is a direct follow up to a previous question where I built out the appropriate related tables/Models. But for sake of clarify, I'll redefine the layout here...
My Models:
order.rb
class Order < ApplicationRecord
belongs_to :user
has_many :quantities
has_many :meals, through: :quantities
end
meal.rb
class Meal < ApplicationRecord
has_many :quantities
has_many :orders, through: :quantities
end
quantity.rb
class Quantity < ApplicationRecord
belongs_to :order
belongs_to :meal
accepts_nested_attributes_for :quantities
end
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 :orders
after_create :add_order
def add_order
self.create_order
end
So each user has 1 order, and they can update the quantity of each meal on their order. I need to display all of this on a 'homepage'(I have made a home controller) of which I was given this iteration as reference:
order.quantities.each do |record|
record.meal.name # for name of associated meal
record.quantity # for quantity of meal
end
But the issue I am having now is incorporating this joined table into the home controller so that the page can actually display the information.
In 1-to-1 relationships, I understoop how to pull the related user's info onto the page, but in this Many-to-Many relationship, the logic is getting lost on me as anytime I bring in the information on the controller, I get an undefined variable.
I don't even want to show my attempt because I think a concept of this type of relationship is lost on me. (The method chaining used in the iteration example makes sense to me looking at it, but then how to deal with that in the controller, not a clue)
If someone could please try to explain what concept is eluding me so that I can understand Many-to-Many relationships better, I feel as though it might clarify a lot of Ruby related confusion I apparently have as well.
To display each order and the quanties for each all you need to do is just a nested iteration:
<% user.orders.each do |order| %>
<div class="order">
<p>Ordered at <%= order.created_at %></p>
<% order.quantites.each do |q| %>
<div class="quantity">
<%= q.meal.name >: <%= q.quantity %>
</div>
<% end %>
</div>
<% end %>
You also have accepts_nested_attributes on the wrong model. It should be:
class Order < ApplicationRecord
belongs_to :user
has_many :quantities
has_many :meals, through: :quantities
accepts_nested_attributes_for :quantities
end
This lets you create nested quantities when along with an order:
Order.create(quantities_attributes: [{ meal_id: 1, quantity: 2 }, { meal_id: 3, quantity: 1 }])
You would setup the nested form like so:
<%= form_with(#order) do |f| %>
<%= fields_for :quantities do |qf| %>
<div class="quantity">
<div class="field">
<%= qf.label :meal_id %>
<%= qf.collection_select :meal_id, Meal.all, :id, :name %>
</div>
<div class="field">
<%= qf.label :quantity %>
<%= qf.number_field :quantity %>
</div>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And the controller:
class OrdersController < ApplicationController
before_action :set_order, only: [:show, :edit, :update, :destroy]
def new
#order = Order.new
# this seeds the form with fields for quantities
10.times { #order.quantities.new }
end
def create
# I'm assuming you have a current_user method
#order = current_user.orders.new(order_params)
if #order.save
redirect_to 'somewhere'
else
render :new
end
end
def update
# I'm assuming you have a current_user method
if #order.update(order_params)
redirect_to 'somewhere'
else
render :new
end
end
private
def set_order
#order = Order.find(params[:order_id])
end
def order_params
params.require(:order).permit(:foo, :bar, quantities_attributes: [:meal_id, :quantity])
end
end

NoMethodError in Pages#profile

I'm working on build a Twitter-like sample app, but I am stuck at creating a following method. I have created a Relationship model and the necessary classes to accomplish the task, but when I load the page, I receive the error "NoMethodError" on this line: <%= form_for(current_user.active_relationships.build, remote: true) do |f| %>
I render the form on the profile page like so:
<%= render '/components/follow_button', :user => User.find_by_username(params[:id]) %>
Here is the form:
<% if current_user.id != user.id %>
<div class="col s12">
<div class="panel panel-default">
<% if !current_user.following?(user) %>
<%= form_for(current_user.active_relationships.build, remote: true) do |f| %>
<div><%= hidden_field_tag :followed_id, user.id %></div>
<%= f.submit "Follow", class: "btn btn-primary" %>
<% end %>
<% else %>
<%= form_for(current_user.active_relationships.find_by(followed_id: user.id),
html: { method: :delete }) do |f| %>
<%= f.submit "Unfollow", class: "btn" %>
<% end %>
<% end %>
</div>
</div>
<% end %>
User.rb:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates_uniqueness_of :email, :case_sensitive => false
validates_uniqueness_of :username, :case_sensitive => false
has_many :posts, dependent: :destroy
has_many :active_relationships, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy
has_many :passive_relationships, class_name: "Relationship", foreign_key: "followed_id", dependent: :destroy
has_many :following, through: :active_relationships, source: :followed
has_many :followers, through: :passive_relationships, source: :follower
def follow(other)
active_relationships.create(followed_id: other.id)
end
def unfollow(other)
active_relationships.find_by(followed_id: other.id).destroy
end
def following?(other)
following.include?(other)
end
end
Relationship.rb
class Relationship < ActiveRecord::Base
belongs_to :follower, class_name: "User"
belongs_to :followed, class_name: "User"
validates :follower_id, presence: true
validates :followed_id, presence: true
end
RelationshipsController:
class RelationshipsController < ApplicationController
def create
user = User.find(params[:followed_id])
current_user.follow(user)
redirect_to(:back)
end
def destroy
user = Relationship.find(params[:id]).followed
current_user.unfollow(user)
redirect_to(:back)
end
end
Any help would be greatly appreciated.
EDIT: Following method used in Routes.rb
devise_for :users
resources :users do
member do
get :following, :followers
end
end
On the form_for documentation, it eventually talks about 'Resource-oriented style' forms
In the examples just shown, although not indicated explicitly, we still need to use the :url option in order to specify where the form is going to be sent. However, further simplification is possible if the record passed to form_for is a resource, i.e. it corresponds to a set of RESTful routes, e.g. defined using the resources method in config/routes.rb. In this case Rails will simply infer the appropriate URL from the record itself
<%= form_for(Post.new) do |f| %>
...
<% end %>
is equivalent to something like:
<%= form_for #post, as: :post, url: posts_path, html: { class: "new_post", id: "new_post" } do |f| %>
...
<% end %>
Looking at your code, since you are not passing a :url option to form_for and you are passing an instance of a model, it's assuming your model was configured in the routes file with resources :relationships, which generates some named route helpers such as relationships_path, the method that it's complaining is missing.
To fix your problem, you need to pass form_for a :url where your controller lives and where it should post to, or update your routes to use the resources :relationships. You can read more information about the resources routing here. If you add
resources :relationships, only: [:create, :destroy]
outside of your devise_for block, you'll end up with 2 new routes for
Prefix Verb URI Pattern Controller#Action
relationships POST /relationships(.:format) relationships#create
relationship DELETE /relationships/:id(.:format) relationships#destroy
and the named helpers relationships_path and relationship_path which your 2 form_for tags are going to be looking for.
Don't forget to restart your server after making changes to your config/routes.rb file to make sure rails picks them up.

param is missing or the value is empty: user - Rails

I have got the following rails app, which allows users to subscribe to widgets. i.e. Many-to-Many through model with Users-to-Widgets through Subscriptions.
My Models:
class Subscription < ActiveRecord::Base
belongs_to :user
belongs_to :widget
validates_uniqueness_of :user_id, scope: :widget_id
end
class User < ActiveRecord::Base
has_many :subscriptions
has_many :widgets, through: :subscriptions
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
class Widget < ActiveRecord::Base
has_many :subscriptions
has_many :users, through: :subscriptions
end
My Controller:
class SubscriptionsController
def edit
#user = current_user
end
def update
#user = current_user
if #user.update(user_subscription_params)
redirect_to #user, notice: "Subscriptions updated"
else
render :edit
end
end
private
def user_subscription_params
params.require(:user).permit(:widget_ids)
end
end
and this is being rendered in views/subscriptions/_forms.html.erb like this:
<%= form_for #user, url: user_subscription_path, method: :patch do |f| %>
<%= f.collection_check_boxes :widget_ids, Widget.all, :id, :name %>
<%= f.submit %>
<% end %>
I am getting the error:
No route matches {:action=>"show", :controller=>"subscriptions"} missing required keys: [:id]
I would be really grateful of any ideas how to fix this.
Edit:
Routes.rb:
Rails.application.routes.draw do
root 'home#index'
resources :widgets
resources :subscriptions
devise_for :users
devise_scope :user do
get '/users/sign_out' => 'devise/sessions#destroy'
end
authenticated :user do
root to: 'home#index', as: :authenticated_root
end
You can try
<%= form_for #user, url: user_subscription_path(#user), method: :patch do |f| %>
<%= f.collection_check_boxes :widget_ids, Widget.all, :id, :name %>
<%= f.submit %>
<% end %>

Rails Devise registration with an additional model

I've searched for about an hour now and found an immense amount of questions describing how to add fields to the Devise user model. However I couldn't find any that explain in a clear way how to add one or multiple models to the registration process.
At registration I want the user to fill out an e-mailaddress, password and in addition my client model, company model and address model (so I have all the information the webapplication needs to run properly).
My models are like this
user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me, :client
belongs_to :client
end
client.rb
class Client < ActiveRecord::Base
attr_accessible :bankaccount, :email, :logo, :mobile, :phone, :website
has_many :users
has_one :company
has_one :address
accepts_nested_attributes_for :company, :address
end
I think the only way to do this is to create my own RegistrationsController so I can do #client = Client.new and then do this in my view:
<%= f.simple_fields_for #client do |ff| %>
<%= f.simple_fields_for :company do |fff| %>
<% field_set_tag t(:company) do %>
<%= ff.input :name %>
<% end %>
<% end %>
<%= f.simple_fields_for :address do |fff| %>
//address inputs
<% end %>
<% end %>
<fieldset>
<legend><%= t(:other) %></legend>
// other inputs
</fieldset>
<% end %>
The reason I need it to work this way is because I have multiple users who can represent the same client (and thus need access to the same data). My client owns all the data in the application and therefor needs to be created before the application can be used.
Okay, it took me about 8 hours but I finally figured out how to make it work (if someone has a better/cleaner way of doing this, please let me know).
First I've created my own Devise::RegistrationsController to properly build the resource:
class Users::RegistrationsController < Devise::RegistrationsController
def new
resource = build_resource({})
resource.build_client
resource.client.build_company
resource.client.build_address
respond_with resource
end
end
After that I just needed to adjust config/routes.rb to make it work:
devise_for :users, :controllers => { :registrations => "users/registrations" } do
get '/users/sign_up', :to => 'users/registrations#new'
end
Also I had an error in my devise/registrations/new.html.erb. It should have been f.simple_fields_for :client instead of f.simple_fields_for #client.
Now it properly creates all the objects for the nested attributes and automatically saves it when saving the resource.

Resources