I'm trying to write a database query and i've been scratching my head at what i'm doing wrong.
Here's the relevant model
class User
has_one :store
has_many :products, through: :store
enum gender: %i[menswear womenswear unisex]
def menswear
self.gender == 'menswear'
end
def womenswear
self.gender == 'womenswear'
end
end
class Product
belongs_to :store
end
and controller is
class UsersController
def index
#male = User.menswear
#female = User.womenswear
#products = Product.all.order('created_at DESC')
end
end
View
<% #male.products.in_groups_of(3, false).each do |group| %>
<% for product in group %>
<%= link_to product_path(product) do %>
<%= image_tag product.secimage_url(:index).to_s, class: "image hide" %>
<%= image_tag product.image_url(:index).to_s, class: "image" %>
<% end %>
<% end %>
<% end %>
Did the same for womenswear aswell.
But i'm getting a NoMethodError
undefined method 'products' for #<User::ActiveRecord_Relation:0x007fbd25e42ac0>
EDIT: I might have been unclear initially, i want the view to show the products sorted by menswear and womenswear, Please help! Thanks
Any pointers on what i'm doing wrong would be appreciated.
Thanks in advance!
Migration
I added gender to Users later and not in the original migration
def up
add_column :users, :gender, :integer
add_index :users, :gender
end
def down
remove_column :users, :gender
end
UPDATE: I changed the users controller to this
def index
#partners = User.partner
#male = User.find_by(gender: 0)
#female = User.find_by(gender: 1)
end
It works but only returns the first instance in both the male and female. I need it to return all of it!
You are mixing has_one :through association with has_many :through association here. You can check proper documentation here. You are having has_one :store and trying to make association has_many :products, through: :store, which is not possible.
Either make it has_one through like:
has_one :store
has_one :product, through: :store
Or for your case make it has_many :through like:
has_many :stores
has_many :product, through: :stores
Or you can remove through from has_many :products, through: :store and make it has_many :products
Choosing solution is upto your requirement.
Try replacing:
def index
#partners = User.partner
#male = User.find_by(gender: 0)
#female = User.find_by(gender: 1)
end
with
def index
#partners = User.partner
#male = User.where(gender: 0)
#female = User.where(gender: 1)
end
Related
Technically, I could get this working, but why my current code doesn't work confuses me. I have a many-to-many relationship in my Events <> Users. This is where my view farts out, saying No route matches: missing required key [:id] ...
<% #event_users.each do |event_user| %>
<%= link_to event_user.user.try(:full_name), user_path(event_user.user) %>
<% end %>
This is my code in my controller. One way that works, one way that doesn't work.
#event = Event.find(params[:id])
#event_users = #event.event_users # This does NOT work
# #event_users = EventUser.where(event_id: 14) # This does work
This is my controller relationships
class User < ActiveRecord::Base
has_many :event_users, dependent: :destroy
has_many :events, through: :event_users
end
class EventUser < ActiveRecord::Base
belongs_to :user
belongs_to :event
validates :user, presence: true
validates :event, presence: true
end
class Event < ActiveRecord::Base
has_many :event_users
has_many :users, through: :event_users
end
What exactly is going on here that I have to query and can't use the association to create a link? When I print out the text, I get the relevant data (the ID), so it should work. I've also tried this below and it still doesn't work.
<%= link_to event_user.user.try(:full_name), user_path(event_user.user_id) %>
You don't need to query #event.event_users, thats what the has_many :through association is for, you can simply use the #event object to get its users:
<% #event.users.each do |user| %>
<%= link_to user.full_name, user_path(user) %>
<% end %>
Note, you can also just pass an object to link_to that rails will automatically use a helper to create a route to users#show, like this:
<%= link_to user.full_name, user %>
In my quiz game Rails project, I have a table for "Participations" that stores information on the user, the quiz category, and the quiz score after a user completes the test.
class CreateParticipations < ActiveRecord::Migration
def change
create_table :participations do |t|
t.references :user
t.string :category
t.boolean :finished, default: false
t.integer :current_question_index, default: 0
t.integer :score, default: 0
t.timestamps
end
end
end
In my user.rb, I specify an association that a user has_many :participations, which allows a user to play multiple quizzes while storing categories/scores in the table.
If I want to show a user a table of his results (so return all Participations results, but only for those that match the user) in a view, can I call that without generating a new controller?
You can just do like below
#in the controller action
#user_participations = Participation.where(user_id: current_user.id)
and just call #user_participations in the view.
#config/routes.rb
resources :users do
resources :participations, path: "results", only: :index #-> url.com/users/:user_id/results
end
#app/controllers/participations_controller.rb
class ParticipationsController < ApplicationController
def index
#user = User.find params[:user_id]
#participations = #user.participations
end
end
#app/views/participations/index.html.erb
<% #participations.each do |participation| %>
<%= participation.score %>
<% end %>
--
If you have your associations set up correctly, you should be using the associative method (#user.participations), which will basically do what Pavan has suggested:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :participations
end
#app/models/participation.rb
class Participation < ActiveRecord::Base
belongs_to :user
end
Users controller
has_many :participations
def participations
#user = User.find(params[:id])
#participations = #users.participations.build(params[:participation_id])
end
end
ParticipationsController
belongs_to :user
In your routes file you can create the route by
GET 'users/:id/participations', to: 'users#participations', as: 'user_participations'
That will give you a user_participations_path route
So if you wanted to link to it you could add
<%= link_to 'Show user games!', user_participations_path(#participations.user) %>
Then in views/users/participations
<% #participations.each do |participation| %>
<%= participation.inspect %>
<% end %>
Let me know how you go!
EDIT
Please not that the has_many and belongs_to declarations should be in the user.rb and participation.rb models respectively. Thanks to #richpeck for picking up the mistake.
In my app there is a many-to-many relationship between recipe and ingredient, everything is working fine but update.
When I update a recipe, i can update any value associated to recipe table in my database but ingredients are not modified
Here is the recipe model
class Recipe < ActiveRecord::Base
after_create :save_implementos
after_create :save_ingredientes
has_many :HasImplemento, dependent: :destroy
has_many :HasIngrediente, dependent: :destroy
has_many :ingredientes, through: :HasIngrediente
has_many :implementos, through: :HasImplemento
#CUSTOM SETTER#
def ingredientes=(value)
#ingredientes = value
end
def implementos=(value)
#implementos = value
#raise #implementos.to_yaml
end
private
#Guarda los implemenos de una receta
def save_implementos
#raise self.id.to_yaml
#implementos.each do |implemento_id|
HasImplemento.create(implemento_id: implemento_id, recipe_id: self.id)
end
end
def save_ingredientes
#raise #ingredientes.to_yaml
#ingredientes.each do |ingrediente_id|
HasIngrediente.create(ingrediente_id: ingrediente_id, recipe_id: self.id)
end
end
Here is the ingredient model
class Ingrediente < ActiveRecord::Base
has_many :has_ingredientes
has_many :recipes, through: :HasIngrediente
end
and Here is the join table
class HasIngrediente < ActiveRecord::Base
belongs_to :recipe
belongs_to :ingrediente
end
I think you just forgot the accepts_nested_attributes_for in your Recipe model:
accepts_nested_attributes_for :ingredients
Your models have a lot of non-conventional code, which is likely the reason for them not working as required:
Use snake_case to define your associations (not CamelCase)
If you're saving nested/associated data, use accepts_nested_attributes_for
Only use callbacks to deal with the model directly; not to deal with other models
#app/models/recipe.rb
class Recipe < ActiveRecord::Base
has_and_belongs_to_many :ingredientes
has_and_belongs_to_many :implementos
accepts_nested_attributes_for :ingredientes, :implementos #-> if you wanted to create new ones
end
Because you're only creating join table records with your callbacks, you can get away with using << or populating the collection_singular_ids value (if you're using existing records):
#app/controllers/recipes_controller.rb
class RecipesController < ApplicationController
def new
#recipe = Recipe.new recipe_params
#recipe.save
end
private
def recipe_params
params.require(:recipe).permit(:implementos_ids, :ingredientes_ids)
end
end
This will allow you to use:
#app/views/recipes/new.html.erb
<%= form_for #recipe do |f| %>
<%= f.collection_select :implementos_ids, Implementos.all, :id, :name %>
<%= f.collection_select :ingredientes_ids, Ingrediente.all, :id, :name %>
<%= f.submit %>
<% end %>
-
I recommend has_and_belongs_to_many because it does not appear that you're populating your join table with any more data than the two model references.
The difference between has_many :through and has_and_belongs_to_many is has_many :through gives you the ability to store extra data in the join table. If you don't need this, has_and_belongs_to_many is far simpler to maintain.
Thus, to answer your question directly, to update your recipe, you can use the following (with my updated code):
#app/views/recipes/edit.html.erb
<%= form_for #recipe do |f| %>
<%= f.collection_select :implementos_ids, Implementos.all, :id, :name %>
<%= f.collection_select :ingredientes_ids, Ingrediente.all, :id, :name %>
<%= f.submit %>
<% end %>
#app/controllers/recipes_controller.rb
class RecipesController < ApplicationController
def edit
#recipe = Recipe.find params[:id]
end
def update
#recipe = Recipe.find params[:id]
#recipe.update recipe_params
end
private
def recipe_params
params.require(:recipe).permit(:implementos_ids, :ingredientes_ids)
end
end
This will set the implementos_ids & ingredientes_ids values for your recipe, which will update the associations automatically.
In our Rails 4 app, there are four models:
class User < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :calendars, through: :administrations
end
class Administration < ActiveRecord::Base
belongs_to :user
belongs_to :calendar
end
class Calendar < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :users, through: :administrations
end
class Post < ActiveRecord::Base
belongs_to :calendar
end
We have routed the corresponding resources with Routing Concerns, as follows:
concern :administratable do
resources :administrations
end
resources :users, concerns: :administratable
resources :calendars, concerns: :administratable
To create a new #calendar, we use the following form:
<h2>Create a new calendar</h2>
<%= form_for(#calendar) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_field :name, placeholder: "Your new calendar name" %>
</div>
<%= f.submit "Create", class: "btn btn-primary" %>
<% end %>
When we embed this form into the user's show.html.erb (so that a user can create a new calendar from his profile), everything works fine.
However, we would like to have a special page, call dashboard, where a user could see all his calendars and create a new one.
We believe the logical url should be /users/:id/administrations.
So, we embedded the above form in the Administration's index.html.erb.
And as soon as we do that and visit for instance /users/1/administrations, we get the following error:
ArgumentError in AdministrationsController#index
First argument in form cannot contain nil or be empty
Extracted source (around line #432):
else
object = record.is_a?(Array) ? record.last : record
raise ArgumentError, "First argument in form cannot contain nil or be empty" unless object
object_name = options[:as] || model_name_from_record_or_class(object).param_key
apply_form_for_options!(record, object, options)
end
EDIT: here is also our Administrations#Controller:
class AdministrationsController < ApplicationController
def to_s
role
end
def index
#user = current_user
#administrations = #user.administrations
end
def show
#administration = Administration.find(params[:id])
end
end
Any idea of what we are doing wrong?
First argument in form cannot contain nil or be empty
The reason is #calendar is not initialised in your controller action, so obviously #calendar is nil. So is the error.
To get your form to work in administrations/index.html.erb, you should be having the below code in your index action of your administrations_controller.
def index
#user = current_user
#administrations = #user.administrations
#calendar = Calendar.new # this one.
end
Hi I'm actually struggling with building a Rails 4 application implementing an attendance model on rails 4, I found maybe two question on stackoverflow but they're posted in 2012 and it failed when i tried following them.
This is the closest one i got on stackoverflow
Edit: I already have a view of classroom and list out the students. And could assign students into the classroom but the problem would be to GET the students into a new attsheet and saving them into attendance
Here's what I currently have now
# Attendance
# take student as a single entry for :attsheet and
# has a :attended (boolean) and remarks as well
class Attendance < ActiveRecord::Base
belongs_to :student
belongs_to :attsheet
end
#Attsheet which means attendance sheet
#has :post_date and :remark
class Attsheet < ActiveRecord::Base
belongs_to :classroom
has_many :attendances
accepts_nested_attributes_for :attendances
end
class Student < ActiveRecord::Base
belongs_to :school
has_and_belongs_to_many :classrooms
has_many :attendances
end
class Classroom < ActiveRecord::Base
belongs_to :school
has_and_belongs_to_many :students
has_many :attsheets
validates :class_name, presence: true
end
I want the classroom to be able to create a new attendance or view attendance archives for each student.
I am able to do this in classroom right now but I'm stuck at what to do next for the controller and view
$ = link_to "New Attendance", new_school_classroom_attsheet_path(#school, #classroom, #attsheet)
In attandances_controller,
class AttendancesController < ApplicationController
before_filter :set_parents
def new
#attendance= #classroom.attendances.new
end
def create
#attendance= #classroom.attendances.new(params[:milestone])
if #attendance.save
redirect_to ....
else
render :action=>:new
end
end
def set_parents
#school= School.find(params[:school_id])
#classroom= #school.classrooms.find(params[:classroom_id])
end
end
and in _form.html.erb of attendacen,
<%= form_for(#school, #classroom, #attendance]) do |f|%>
<% if #attendance.errors.present? %>
<ul class="warning">
<% #attendance.errors.full_messages.each do |message| %>
<li><%= message%></li>
<% end %>
</ul>
<% end %>
<h2>Attendance</h2>
.........
<%= f.submit button %>
<% end %>
this will submit fotm to create action of attendance
I found the solution by doing
I changed attsheet to attendance_list
def new
#attendance_list = #classroom.attendance_lists.new
#attendance_list.attendances = #classroom.student_ids.map do |student_id|
#attendance_list.attendances.build(student_id: student_id)
end
end
def create
#attendance_list = #classroom.attendance_lists.new(attendance_list_params)
#attendance_list.classroom_id = params[:classroom_id]
respond_to do |format|
if #attendance_list.save
format.html {redirect_to school_classroom_path(#school, #classroom), notice: "You added the attendance!" }
else
redirect_to new_school_attendance_list_path(attendance_list_params)
end
end
end
with simple fields
= f.simple_fields_for :attendances do |g|
= g.input :student_id, as: :hidden
...... more fields ...