I have a funding table in which there is a field name_of_organisation which displays a list of organisations from organisation table. In the list I have an option "Not Listed". If notlisted is selected a further form opens to add organisation. But that organisation details get added in the funding table. What I want is on funding show page if new organisation details are added admin can verify the organisation details and should have a button to click on so that all those organisation details in funding table get added in the organisation table. I need help with query for add organisation button on show.html.erb page for funding to add organisation details from funding to organisation table.
schema for funding table
create_table "fundings", force: :cascade do |t|
t.string "type_of_activity"
t.string "season"
t.text "activity_details"
t.string "name_of_organisation"
t.string "city"
t.string "province"
t.string "postal_code"
t.string "telephone_number"
t.text "address"
t.integer "organisation_id"
end
schema for organisation table
create_table "organisations", force: :cascade do |t|
t.string "name_of_organisation"
t.text "address"
t.string "city"
t.string "province"
t.string "postal_code"
t.string "telephone_number"
end
Show.html.erb (funding)
<%unless #funding.organisation.blank?%>
<p><strong>Name of the Organisation:</strong>
<%= #funding&.organisation&.name_of_organisation %></p><br>
<%end%>
<% if #funding.name_of_organisation.present? %>
<%= #funding.name_of_organisation %>
<% if current_user.superadmin? %>
<%= link_to 'Add Organisation', '' %>
<% end %>
<% end %>
You should use the ID of the organization instead of the name to link the two models together. Thats how associations in ActiveRecord work.
Your attempt has a huge flaw in that editing the name of the organization would break any assocation. IDs don't change.
Start by generating a migration to add a foreign key column to the fundings table:
# rails g migration add_organization_to_fundings organization:belongs_to
how class AddOrganizationToFundings < ActiveRecord::Migration[5.0]
def change
add_reference :fundings, :organization, foreign_key: true
end
end
If you have any existing data that is linked by the name you need to iterate through and fix these records:
Funding.find_each(batch_size: 100) do |f|
organization = Organization.find_by(name: f.name_of_organisation)
f.update!(organization_id: organization.id)
end
You should then write a migration to remove the fundings.name_of_organisation column.
You then need to setup the proper assocations:
class Funding < ApplicationRecord
belongs_to :organization
end
class Organization < ApplicationRecord
has_many :fundings
end
You can then create a select tag by using the form option helpers:
<%= form_for(#funding) do |f| %>
<%= f.select :organization_id, Organization.all, :id, :name %>
<% end %>
I know it's infuriating when you ask "How do I do this?" on stackoverflow and they say "Don't", but in this instance it's pretty cut and dry. Don't do it this way.
You're storing the organization name and address and such twice, once for the funding and once for the organization. This is a very bad practice, which will bite you when it comes time to change anything at all. You want to store the organization details the organization table, and that table only. Strip it out of your funding table, and add a foreign key to reference which organization it belongs to.
These are pretty basic concepts, you really want to take a little time and learn about databases before going further. Find a decent lecture, article, or tutorial on "relational database basics" and work through it. It doesn't have to be (and probably won't be) specific to rails.
After that, read up on Activerecord, especially relations.
To solve your admin approval problem, what I would do is add an "approved" boolean flag to the organization table and a custom controller action only available to admins to approve it. You can go further and create an "approved" scope for normal users, and a "pending" scope or something visible to admins. That's only one possible solution of many, though.
In order to 'Add Organisation' .. I would run get the path to the method of logic you're trying to do and remote:true the logic depending if you're planning to render with js or redirect to a new screen.
Related
I am creating a webshop with products. I sell digital game accounts.
I have invented a dropdown menu, with f.collection_select, for the user to choose which server the account must belong to.
If the user selects a server, lets say "North America", I want the page to show the accounts which I have that belong to the server "North America". I have set up two models, the server model, this model just contains name:string, and the model has_many :accounts.
Next model I have is account.rb. This model stores all information in regards to account, and belongs_to :server.
I use this form for selection of server, in my views/accounts/index.html.erb
I can see that it works, and shows my servers, which I have created in the database.
<%= form_with do |f| %>
<%= f.collection_select(:server_ids, Server.all, :id, :name, remote: true) %>
<% end %>
class CreateAccounts < ActiveRecord::Migration[6.0]
def change
create_table :accounts do |t|
t.string :name
t.string :password
t.string :BE
t.integer :level
t.integer :price
t.references :server, null: false, foreign_key: true
t.timestamps
end
end
end
class CreateServers < ActiveRecord::Migration[6.0]
def change
create_table :servers do |t|
t.string :name
t.timestamps
end
end
end
This is how the site looks atm with the dropdown:
So here I have selected EUW server. When I change it to NA, I want the page to display the accounts I have in the association Server.find(name:"Europe West (EUW)".accounts
Here is a video, that shows what I am going for:
https://www.youtube.com/watch?v=bZUxS5oMMOw
Basically, all I need is a template_id field in my business table to be assigned correctly so that if I did Business.first.template it would return the result of the current assigned template for that business. At the moment I get I am just getting 'nil'
In my project a Business belongs_to a template (I believe this puts the primary key in the template table and the foreign key in the business table).
class Business < ActiveRecord::Base
belongs_to :template
class Template < ActiveRecord::Base
has_many :businesses
When the user fills out a form for a 'new business' they select the template they wish to use. The templates table is already filled with 3 templates, template_id, 0, 1, 2 (so I cant really work out if anything needs to be 'created'). The user is limited through the form to select only one of 3 templates (radio buttons).
When submitting the form and creating the business the link between the business and the template is currently not created. I don't have anything about the template creation in my business class because I cant work out what would need to be created, the template records already exist in the template table and are static.
Business Controller
def new
#business = current_user.businesses.build
#business.addresses.build
end
# POST /businesses
def create
#business = Business.new(business_params)
#business.users << current_user
if #business.save
redirect_to #business, notice: 'Business was successfully created.'
else
render action: 'new'
end
end
def business_params
params.require(:business).permit(:name, :email, :template_id, addresses_attributes [:number, :street, :suburb, :state, :country], template_attributes: [:name])
I am not sure if I should be assigning template_id myself or doing something with 'build_template'
Schema
create_table "businesses", force: true do |t|
t.datetime "created_at"
t.datetime "updated_at"
t.string "name"
t.string "description"
t.string "sub_heading"
t.string "email"
t.integer "template_id"
end
create_table "templates", force: true do |t|
t.datetime "created_at"
t.datetime "updated_at"
t.string "name"
t.integer "cost"
end
I am not sure if I should be assigning the value as either 0, 1 or 2 directly from the form submitted by the user to template_id in the business table or if I should be allowing nested attributes as I did with the addresses table.
Any help is appreciated.
Thanks
The foreign key to template id will be fine though. It is what ties an instance of Business to a and instance of Template.
You aren't creating a template, you are selecting one already from a list of created templates. You can access a business's template should be as simple as Business.find(id).template where Id is the id of the business you want knowledge about.
I'm working on a Rails app where Users can have multiple roles, e.g. Manager, Employee, Admin, etc.
STI doesn't work in this situation, due to multiple roles, but I'd still like to keep role-related data in different tables if at all possible.
So for right now, my schema looks something like this:
create_table :roles do |t|
t.string :name
t.timestamps
end
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :email, :default => "", :null => false
t.timestamps
end
create_table :roles_users, :id => false do |t|
t.references :role, :user
end
And my User/Role models both have has_and_belongs_to_many relationships with each other.
So if, for example, I need the Manager to have_many Employees, is that possible with this setup? Is it possible for a User with the Manager role to have a Manager-specific attribute like secret_manager_information? Or do I need to re-think my approach?
Seeing as how Managers need to keep track of Employees (and in general other roles may need to keep track of other special data), I'd say that each role is different enough that they should get their own tables (assuming that you don't have too many roles).
For example, I would create a Manager and an Employee model:
class Manager
attr_accessible :user_id
has_many :employees
end
class Employee
attr_accessible :user_id, :manager_id
belongs_to :manager
end
Any user that is a Manager will have a record in the Manager table with user_id = user.id.
Any user that is an Employee will have a record in the Employee table with user_id = user.id and manager_id = (the id of the corresponding manager record)
I have a simple HABM relationship set up between users and children.
If a child belongs to you, I want you to see the child AND the name of other users that this child object belongs to. For some reason I cannot print the name of the other users the child belongs to.
I select as such:
#children = Child.all(:include => :users, :conditions => ["users.id = ? AND enrolled = ?", current_user.id, true])
and try to print as such:
<% for user in child.users%>
<% if can? :manage, Child %>
<a rel='tipsy'><%= link_to '[#{user.first_and_last_name}]', edit_child_path(child), :title => "#{user.updateChoice}"%></a>
<%else%>
<a rel='tipsy'><%= link_to '[#{user.first_and_last_name}]', new_parentnote_path, :title => "#{user.updateChoice}"%></a>
<%end%>
<%end%>
It selects the right children but DOES NOT print the other users' name. Only the current user's name.
If I select all children Child.all everything works as expected. All names get printed which tells me it is not my authentication system doing something fishy but something else...probably the way I select the children although I tried several ways =(
I am not sure if I am missing something really obvious but this has puzzled me for hours.
Any help is greatly appreciated. Thanks.
EDIT - Add Schema
As requested bellow here is the schema. The relationship is set up fine as far as I can tell. It is just getting multiple users based on current_user that is not happening as explained above. If I use the query above even though the child has multiple users (I see that by doing a child.count) it will only print the current user's name for some reason it is not fetching the other users name that the child belongs to as well.
create_table "children_users", :id => false, :force => true do |t|
t.integer "child_id"
t.integer "user_id"
end
Then I have children.
create_table "children", :force => true do |t|
t.string "first_name"
t.string "last_name"
t.boolean "enrolled", :default => true
t.datetime "unenrolled_datetime"
end
and users
create_table "users", :force => true do |t|
t.string "email"
t.string "encrypted_password"
t.string "first_name"
t.string "last_name"
........ other stuff to reset password etc
end
You're trying to get the children of a user, and at the same time, get all the other parents?
An easy way to list the children of a user and display the parents of each children would be:
#children = current_user.children
<%= #children.each do |child| %>
<h2><%= child.first_name %></h2>
<%= #child.parents.each do |parent| %>
<p><%= parent.first_name %></p>
<% end %>
<% end %>
ps:
in Children model
has_many :children_users
has_many :parents, :through => :children_users, :class_name => "User", :source => :user
I belive it's the condition "users.id = ? ", current_user.id that makes loading only the children of the current_user, and subsequently when you iterate over those the only user there, is current user.
What you probbly want is select based on children.user_id:
#children = Child.where(user_id: current_user.id, enrolled: true).includes(:users)
How would a Polymorphic Association (here: Comments) be itself associated with different types of Authors?
Starting from …
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => :true
end
… I'd need to have one author being from model Hosts, ID 5 and another one from Users, 2.
How could path helpers look like…
<%= link_to comment.author.name, user_path(comment.author) %>
… when "user_path" or "host_path" are dynamic, depending on the author model?
EDIT***
There are Events, Places etc. that can have comments like so:
has_many :comments, :as => :commentable
To the polymorphic Comment model i would like to add IDs and Types to refer to Authors of comments:
create_table "comments", :force => true do |t|
t.text "content"
t.integer "commentable_id"
t.string "commentable_type"
t.integer "author_id"
t.string "author_type"
end
An Events page displays comments, and clicking on an author name should take me either to User(5) oder AnotherModel(2), depending on who wrote the comment.
I'd like to know how everybody handles this kind of situation. Should I think about adding a second polymorphic "middle layer", such as "profile", that could hold the subclasses "User", "Host" and so forth?
EDIT 2
Having only one User model would make life easier here obviously, but that cannot be done for other reasons. And in general i'm interested how this could be organized well.
Simply putting
<%= link_to comment.author.name, comment.author %>
should do the trick. If you want more flexibility, I would suggest
link_to ..., action_in_host_path(comment.author) if comment.author.kind_of? Host
This is what I've used in the past (in a view helper), but it uses an eval:
def model_path(model, options = {})
{:format => nil}.merge(options)
format = (options[:format].nil? ? 'nil' : "'#{options[:format].to_s}'")
eval("#{model.class.to_s.downcase}_path(#{model.id}, :format => #{format})")
end
Use like this:
<%= link_to comment.author.name, model_path(comment.author) %>
Would polymorphic_url help?
<%= link_to comment.author.name, polymorphic_url(comment.commentable)
%>