has_many :through rails - ruby

I want to get user1 to accept requests from other users to join user1s post as contributors and be listed out if user1 accepts them
Can't seem to get it to work - Here's my setup:
has_many :through
I'm thinking:
post model
class Post < ActiveRecord::Base
#Join table associations
has_many :group_requests, class_name: "Group",
foreign_key: "requester_id",
dependent: :destroy
has_many :group_users, class_name: "Group",
foreign_key: "accepted_id",
dependent: :destroy
has_many :requester, through: :group_requests
has_many :accepted, through: :group_users
def request(other_post)
group_requests.create(accepted_id: other_post.id)
end
# Unfollows a user.
def unrequest(other_post)
group_requests.find_by(accepted_id: other_post.id).destroy
end
# Returns true if the current user is following the other user.
def accepted?(other_post)
requesting.include?(other_post)
end
user model
class User < ActiveRecord::Base
#Join table associations
belongs_to :group
group model
class Group < ActiveRecord::Base
belongs_to :requester, class_name: "Post"
belongs_to :accepted, class_name: "Post"
validates :requester_id, presence: true
validates :accepted_id, presence: true
end
CreatePosts Migration
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.string :title
t.text :content
t.timestamps null: false
end
end
end
DeviseCreateUsers Migration
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticatable
t.integer :post_id
t.string :email, null: false, default: ""
AddUserIdToPosts
class AddUserIdToPosts < ActiveRecord::Migration
def change
add_column :posts, :user_id, :integer
add_index :posts, :user_id
end
end
CreateGroup Migration
class CreateGroups < ActiveRecord::Migration
def change
create_table :groups do |t|
t.integer :requester_id
t.integer :accepted_id
t.timestamps null: false
end
add_index :groups, :requester_id
add_index :groups, :accepted_id
add_index :groups, [:requester_id, :accepted_id], unique: true
end
end
Post Controller
def accepted
#title = "Accepted"
#post = Post.find(params[:id])
#users = #user.accepted.paginate(page: params[:page])
render 'show_accepted'
end
def requester
#title = "Requesters"
#post = Post.find(params[:id])
#users = #user.requester.paginate(page: params[:page])
render 'show_requester'
end
private
def post_params
params.require(:post).permit(:title, :content, :image)
end
Post Show
<% #post ||= current_user(#post) %>
<div class="stats">
<a href="<%= accepted_post_path(#post) %>">
<strong id="following" class="stat">
<%= #post.accepted.count %>
</strong>
following
</a>
<a href="<%= requester_post_path(#post) %>">
<strong id="followers" class="stat">
<%= #post.requester.count %>
</strong>
followers
</a>
</div>
Any suggestions?

You could try this ---
as i think p is your post and you want to get all user_ids.
p.group_members.map{|gm|gm.user_id} #list of all ids in array
### OR try this
p.users #list of all users in array
#if you want to collect ids then
p.users.collect(&:id)
I think it should be helpful for you

Related

Using checkboxes to pass multiple strings to array in migration with ruby

Im looking to have a user create a post where they specify what instruments they play. There should be a checkbox for each instrument so the user can select the ones that apply to the post. I was able to display the instruments and their checkboxes in the post creation but I cannot figure out how to save them to the post. I get error ActiveRecord::AssociationTypeMismatch.
Displaying all instruments and passing integers for each (Id like to pass strings)
<% Instrument.all.each do |instrument| %>
<%= check_box_tag "post[instruments][]", instrument.id %>
<%= instrument.name %> <br>
<% end %>
<div class="actions">
<%= form.submit %>
</div>
Migration to receive array of integers
class AddTagsToPost < ActiveRecord::Migration[5.2]
def change
add_column :posts, :instruments, :integer, array: true, :default => []
end
end
schema.rb
create_table "instruments", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "posts", force: :cascade do |t|
t.bigint "category_id"
t.string "title"
t.text "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "account_id"
t.integer "instruments", default: [], array: true
t.index ["account_id"], name: "index_posts_on_account_id"
t.index ["category_id"], name: "index_posts_on_category_id"
end
post.rb model
class Post < ApplicationRecord
belongs_to :category
belongs_to :account
has_many :instruments
validates :title, presence: true, length: { minimum: 3 }
validates :content, presence: true, length: { maximum: 500 }
end
instrument.rb model
class Instrument < ApplicationRecord
belongs_to :posts, optional: true
end
Private end of the posts_controller.rb
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Only allow a list of trusted parameters through.
def post_params
params.fetch(:post, {}).permit(:title, :content, :category_id, instruments:[])
end
end

Multi model sign up with clearance in Rails 4

So I want to create a Company while signing up as a new user to my application. I use https://github.com/thoughtbot/clearance for authentication.
I have these 2 migrations:
class CreateCompanies < ActiveRecord::Migration
def change
create_table :companies do |t|
t.string :name, null: false
t.string :email, null: false
t.attachment :logo
t.timestamps null: false
end
end
end
And
class CreateClearanceUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :email, null: false
t.string :encrypted_password, limit: 128, null: false
t.string :confirmation_token, limit: 128
t.string :remember_token, limit: 128, null: false
t.string :first_name
t.string :last_name
t.attachment :avatar
t.integer :company_id
t.timestamps null: false
end
add_index :users, :email, unique: true
add_index :users, :remember_token
end
end
My models look like this:
class User < ActiveRecord::Base
include Clearance::User
belongs_to :company
end
class Company < ActiveRecord::Base
has_many :users
accepts_nested_attributes_for :users
end
This is my altered Clearance controller:
class Clearance::UsersController < ApplicationController
before_filter :redirect_signed_in_users, only: [:create, :new]
skip_before_filter :require_login, only: [:create, :new]
skip_before_filter :authorize, only: [:create, :new]
def new
#user = User.new
#user.build_company
render template: "users/new"
end
def create
#user = User.new(user_params)
if #user.save
sign_in #user
redirect_back_or url_after_create
else
render template: "users/new"
end
end
private
def avoid_sign_in
warn "[DEPRECATION] Clearance's `avoid_sign_in` before_filter is " +
"deprecated. Use `redirect_signed_in_users` instead. " +
"Be sure to update any instances of `skip_before_filter :avoid_sign_in`" +
" or `skip_before_action :avoid_sign_in` as well"
redirect_signed_in_users
end
def redirect_signed_in_users
if signed_in?
redirect_to Clearance.configuration.redirect_url
end
end
def url_after_create
Clearance.configuration.redirect_url
end
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password, companies_attributes: [:id, :name])
end
end
And at last my form:
<div class="form-item">
<%= form.label :first_name %>
<%= form.text_field :first_name, type: "text" %>
</div>
<div class="form-item">
<%= form.label :last_name %>
<%= form.text_field :last_name, type: "text" %>
</div>
<div class="form-item">
<%= form.label :email %>
<%= form.text_field :email, type: "email" %>
</div>
<div class="form-item">
<%= form.fields_for :companies do |builder| %>
<label>Company</label>
<%= builder.text_field :name, type: "text" %>
<%end%>
</div>
<div class="form-item">
<%= form.label :password %>
<%= form.password_field :password %>
</div>
I can perfectly submit my form, but my company_id is nil when finding the user object in rails console.
Anyone have an idea what I am doing wrong?
Thanks in advance!
You need to use the singular:
= form.fields_for :company
and in your controller:
company_attributes # instead of companies_attributes
and you have one thing in the wrong model! You want to save a company with the user so you need to move accepts_nested_attributes_for to user.rb
accepts_nested_attributes_for :company

Displaying Current User in view through a polymorphic association

I am attempting to display the current users name once they are logged in.
Therefore at the top of the page it would say "Logged in as Patrick". However I have a polymorphic association set up whereby every user that signs up is either a player or a coach.
The polymorphic association is under the label or :tennis_player as both coach and player play tennis.
The code for the view is below.
<div class="container">
<header>
<div class="logo">
<%= link_to(image_tag 'tennis_ball.png', :width => 100, :height => 100) %>
</div>
<div class="slogan">
<h3>Setfortennis</h3>
</div>
<div id="user_nav">
<% if current_user? %>
Logged in as <%= #current_user %>
<%= link_to "log out", log_out_path %>
<% else %>
<%= link_to "Sign Up", sign_up_path %> or
<%= link_to "Log in", log_in_path %>
<% end %>
</div>
</header>
</div>
Here is my application controller
helper_method :current_user?
before_filter :get_user
def current_user?
!!current_user
end
def current_user
#current_user ||= session[:user_id] &&
User.find_by_id(session[:user_id])
end
def check_logged_in
redirect_to( new_session_path, :notice => "You must be logged in to do that!") unless current_user?
end
def get_user
#user = User.new
end
end
And here are my models. Anything else needed to solve let me know!
class Player < ActiveRecord::Base
attr_accessible :about, :club, :first_name, :last_name, :profile_picture, :racket, :ranking, :image
has_attached_file :image, styles: {
thumb: '100x100>',
square: '200x200#',
medium: '300x300>'
}
has_many :videos
has_one :user, :as => :tennis_player
end
class Coach < ActiveRecord::Base
attr_accessible :about, :club, :first_name, :last_name, :profile_picture, :ranking
has_one :user, :as => :tennis_player
end
User Model.
class User < ActiveRecord::Base
attr_accessible :email, :password_hash, :password_salt, :password, :password_confirmation
attr_accessor :password
belongs_to :tennis_player, :polymorphic => true
before_save :encrypt_password
validates_confirmation_of :password
validates_confirmation_of :password, :on => :create
validates_confirmation_of :email
validates_uniqueness_of :password
def self.authenticate(email, password)
user = find_by_email(email)
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
end
You just need to store the right id whenever you create a session. But I would change the design a little. Instead of having two separate tables for Player and Coach, you can create a base class User, and inherit from it.
class User < ActiveRecord::Base
attr_accessible :about, :club, :first_name, :last_name, :profile_picture, :ranking
end
class Player < User
end
class Coach < User
end

active_admin - display a list of items that belongs to another item

I am trying to display somehow the line items for the order in the active_admin order show page, no luck..
here are the relations between models:
order.rb
class Order < ActiveRecord::Base
has_many :line_items, :dependent => :destroy
# ...
validates :name, :address, :email, :presence => true
validates :pay_type, :inclusion => PAYMENT_TYPES
end
line_item.rb
class LineItem < ActiveRecord::Base
belongs_to :order
belongs_to :product
belongs_to :cart
def total_price
product.price * quantity
end
end
active_admin order.rb
ActiveAdmin.register Order do
show do
attributes_table :name, :email, :address, :pay_type, :created_at, :updated_at
end
end
active_admin line_item.rb
class LineItem < ActiveRecord::Base
belongs_to :order
belongs_to :product
belongs_to :cart
def total_price
product.price * quantity
end
end
when I click show order, it must display the items for this order.. In application's show file I did it with
<%= render #order.line_items %>
_line_items.html.erb
<!-- START_HIGHLIGHT -->
<% if line_item == #current_item %>
<tr id="current_item">
<% else %>
<tr>
<% end %>
<!-- END_HIGHLIGHT -->
<td><%= line_item.quantity %>×</td>
<td><%= line_item.product.title %></td>
<td class="item_price"><%= number_to_currency(line_item.total_price) %></td>
</tr>
and the items are in the page, but in Active_Admin I don't know how to make it work.. Please help. Thank you for your time.
Solved
Thanks to bruno077 I managed to finally get the line_items in the order show_page in ActiveAdmin
show do |order|
panel "Customer details" do
attributes_table_for order, :first_name, :last_name, :card_type, :created_at, :ip_address
end
panel("Products for this order") do
table_for(order.line_items) do
column "Product" do |item|
item.product.title
end
column "Price" do |item|
item.product.price
end
column "Quantity" do |item|
item.quantity
end
end
end
end
I got the ID of the product for now, but it's not far from here to get what I want. Cheers!
Something like this might work:
ActiveAdmin.register Order do
show do |order|
div do
panel("Items") do
table_for(order.line_items) do
column :quantity
column "Title" do |i|
i.product.title
end
column "Price" do |i|
number_to_current(i.total_price)
end
end
end
end
end
end
Another unrelated example which might give you a hint:
# => Show
show :title => :date do |gallery|
panel "Galería" do
attributes_table_for gallery, :name, :description, :date
end
panel "Fotos" do
table_for(gallery.gallery_files) do
column "Título", :title
column "Fecha", :date
column "Foto" do |image|
image_tag image.file.url(:thumb).to_s
end
end
end
end

Nested Form Doesn't Save Nested Model Rails 3

I am trying to create a form that creates a game and game_players at the same time.
The problem I am having is that when I submit the form, the game is created, but the game_players are not.
I've looked around, but haven't found any helpful answers.
Game Model
class Game < ActiveRecord::Base
belongs_to :league
has_many :game_players, :dependent => :destroy
accepts_nested_attributes_for :game_players
attr_accessible :league_id, :game_date
validate :league_id, :presence => true
end
Game_Player Model
class GamePlayer < ActiveRecord::Base
belongs_to :game
has_many :users
validate :game_id, :presence => true
validate :user_id, :presence => true
end
Game Controller
class GamesController < ApplicationController
def new
#title = "New Game"
#game = Game.new
3.times { #game.game_players.build }
end
def create
#game = Game.new(:league_id => cookies[:league_id])
if #game.save
flash[:success] = "Succesfully Created Game"
redirect_to League.find_by_id(cookies[:league_id])
else
#title = "New Game"
render 'new'
end
end
Form
<%= form_for #game do |f| %>
<%= f.fields_for :game_players do |builder| %>
<p>
<%= builder.label :user_id, "User" %><br />
<%= builder.text_field :user_id %><br />
</p>
<% end %>
<p><%= f.submit "Submit" %></p>
<% end %>
most likely you need to pass :game_players_attributes to attr_accessible since .new respect mass-assignment security

Resources