As a noob, I have done this a few times, but I always struggle with the strong params. I rolled a new model and controller for uploading a link to a video.
Here is my code:
new_vids_controller.rb
class NewVidsController < ApplicationController
def index
#vids = NewVid.all
end
def new
#vid = NewVid.new(vid_params)
end
def create
if current_user
#vid=NewVid.new(vid_params)
#vid.user_id = current_user.id
if #vid.save
flash[:notice] = "Video Submitted"
redirect_to videos_path
else
flash[:error] = "Error: Vid not Submitted"
redirect_to videos_path
end
else
flash[:error] = "You Must Be Signed In To Submit Videos!"
store_location
redirect_to signin_path
end
end
end
private
def vid_params
params.require(:new_vid).permit(:vid_link, :vid_body, :user_id)
end
new.html.erb
<%= form_for #vid do |f| %>
<%= f.text_field :vid_link, title: "Video Link", placeholder: "Video Link" %>
<%= f.text_field :vid_body, title: "Description", placeholder: "Video Description" %>
<%= f.submit "Submit Link", class: "button tiny" %>
Thanks for helping a noob!
Your new action should be:
#vid = NewVid.new
There are no params to validate there.
Related
I am starting a new Rails 7 app and recently found out that we can't use ujs anymore :( I found a plugin called mrujs which is working correctly to send my forms remotely to the server. I am also using stimulus to handle various javascript functions on the page.
The issue that I'm having is my response back after ajax:success processes is not iterable:
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
Below is my HTML, Rails, and Stimulus Code:
HTML
<%= form_with model: Article.new, html: { data: { remote: true, type: "html", "action": "ajax:success->modal-forms#onPostSuccess ajax:error->modal-forms#onPostError" } } do |f| %>
<%= f.label :title, "Article Title" %>
<%= f.text_field :title, class: "form-control" %>
<%= f.submit "Save Article", class: "btn btn-primary" %>
<% end %>
Ruby / Rails
def create
#article = Article.create(article_params)
if #article.errors.any?
render partial: 'error', article: #article, status: :bad_request
else
render #article
end
end
This returns a basic html page that would be inserted into another location within the page.
<li><%= #article.title %></li>
Stimulus Action
onPostSuccess(event) {
event.preventDefault()
const [data, status, xhr] = event.detail
// This is where I get the issue of 'Not Iterable'
}
event.detail gives me the not iterable error. Does anyone know how I can get my response from rails to be formatted so the [data, status, xhr] section will actually work?
If hotwire or turbo is needed for this an example would be extremely helpful :)
Thanks
Eric
This may not be the correct way but it does work:
html
<div data-container="remote">
<%= form_with model: Person.new, html: { data: { "action": "submit->remote#submit" } } do |f| %>
<%= f.text_field :first_name %>
<%= f.submit :submit %>
<% end %>
</div>
peole rails controller
def create
#person = Person.new(person_params)
if #person.save
render json: #person
else
render partial: 'people/person', locals: { person: #person }, status: :unprocessable_entity
end
end
remote stimulus controller
submit(event) {
event.preventDefault()
fetch(event.target.action, {
method: 'POST',
body: new FormData(event.target),
}).then(response => {
console.log(response);
if(response.ok) {
return response.json()
}
return Promise.reject(response)
}).then(data => {
console.log(data)
}).catch( error => {
console.warn(error)
});
}
Locally it records a string as expected and on Heroku it records a fixnum...
A user can create a wish and select an area where he wants to see a concert. In order to receive an email if a concert matches his wish.
I have a hash sotred in my application_helper.rb as a constant
DEPARTMENTS = {
"01" => "Ain",
"02" => "Aisne",
"03" => "Allier"
#........
}
My create method in the wanted_concerts_controller.rb looks like this
def create
#wanted_concert = WantedConcert.new(wanted_concerts_params)
#wanted_concert.user_id = current_user.id
if #wanted_concert.save!
redirect_to wanted_concerts_path, notice: "Ton souhait est bien enregistré"
else
render :new , alert: "Oups recommence!"
end
end
private
def wanted_concerts_params
params.require(:wanted_concert).permit(:department, :user_id)
end
In the new.html.erb file I can make my wish
<%= simple_form_for(#wanted_concert) do |f| %>
<%= f.input :department, prompt: "Choisi une région", label: false, collection: ApplicationHelper::DEPARTMENTS.map { |k, v| v } %>
<%= f.submit "Valider", class: "btn btn-success" %>
<% end %>
And this is my index.html.erb where the wishes are displayed
<% #wanted_concerts.each do |wanted| %>
<li> <%= wanted.department %> <%= link_to "Supprimer", wanted_concert_path(wanted), method: :delete %></li>
<% end %>
So locally if I chose for exemple Ain
the index display Ain
and on Heroku if chose Ain
it display 0
So On Heroku console I did:
irb(main):004:0> c = WantedConcert.last
D, [2018-03-04T13:31:54.314672 #4] DEBUG -- : WantedConcert Load (1.3ms) SELECT "wanted_concerts".* FROM "wanted_concerts" ORDER BY "wanted_concerts"."id" DESC LIMIT $1 [["LIMIT", 1]]
=> #<WantedConcert id: 21, department: 0, user_id: 1, created_at: "2018-03-04 13:02:16", updated_at: "2018-03-04 13:02:16">
irb(main):005:0> c.department.class
=> Integer
irb(main):006:0>
I found help.
I did a naughty mistake, I renamed a field in an old migration instead of renaming in a new....
So this may help someone facing a smiliar error...
I'm trying to use AJAX on a friendships list where the "Request Friendship" button turns into a "Cancel Request" button and then back again if clicked a second time. The first click works, the ajax on the "Cancel Request" button does not.
On line 2 of the destroy.js.erb I get a:
undefined method `id' for nil:NilClass
I know it's not working because the user_id is not passed in the URL for the destroy as it is for the create, but I don't know how to fix it.
Friendships Controller
before_action :authenticate_user!
before_action :set_user, only: [:create]
before_action :set_friendship, only: [:destroy, :accept]
def create
#friendship = current_user.request_friendship(#user)
respond_to do |format|
format.html {redirect_to users_path, notice: "Friendship Requested"}
format.js
end
end
def destroy
#friendship.destroy
respond_to do |format|
format.html {redirect_to users_path, notice: "Friendship Removed"}
format.js
end
end
def accept
#friendship.accept_friendship
#friendship.create_activity key: 'friendship.accepted', owner: #friendship.user, recipient: #friendship.friend
#friendship.create_activity key: 'friendship.accepted', owner: #friendship.friend, recipient: #friendship.user
respond_to do |format|
format.html {redirect_to users_path, notice: "Friendship Accepted"}
format.js
end
end
private
def set_user
#user = User.find(params[:user_id])
end
def set_friendship
#friendship = Friendship.find(params[:id])
end
Create JS
$('.js-not-friend-btn').bind('ajax:success', function() {
$('.action-button-for-<%= #user.id %>').html('<%= j action_buttons(#user) %>');
});
Destroy JS
$('.js-cancel-request-btn').bind('ajax:success', function() {
$('.action-button-for-<%= #user.id %>').html('<%= j action_buttons(#user) %>');
});
Users Helper
def action_buttons(user)
case current_user.friendship_status(user) when "friends"
link_to "Cancel Friendship", friendship_path(current_user.friendship_relation(user)), method: :delete, :remote => true, class: "js-cancel-friendship-btn btn btn-danger btn-xs mr10"
when "pending"
link_to "Cancel Request", friendship_path(current_user.friendship_relation(user)), method: :delete, :remote => true, class: "js-cancel-request-btn btn btn-danger btn-xs mr10"
when "requested"
link_to("Accept Friendship", accept_friendship_path(current_user.friendship_relation(user)), method: :put, :remote => true, class: "js-accept-friendship-btn btn btn-success btn-xs mr10") +
link_to("Decline", friendship_path(current_user.friendship_relation(user)), method: :delete, :remote => true, class: "js-decline-friendship-btn btn btn-default btn-xs mr10")
when "not_friends"
link_to "Add as Friend", friendships_path(user_id: user.id), method: :post, :remote => true, class: "js-not-friend-btn btn btn-success btn-xs mr10"
end
end
Thanks for any help you can offer.
I had to add the following line to my destroy action in order to use #user in the destroy.js.erb:
#user = #friendship.user == current_user ? #friendship.friend : #friendship.user
I've been struggling with this for a while now and can't figure out what is happening. I'm working my way through Michael Hartl's Rails tutorial and have come to have an issue with some of my tests. These are the failing test results:
Failures:
1) User pages signup with invalid information should not create a user
Failure/Error: expect { click_button submit }.not_to change(User, :count)
ActionController::ParameterMissing:
param not found: user
# ./app/controllers/users_controller.rb:61:in `user_params'
# ./app/controllers/users_controller.rb:21:in `create'
# ./spec/requests/user_pages_spec.rb:89:in `block (5 levels) in <top (required)>'
# ./spec/requests/user_pages_spec.rb:89:in `block (4 levels) in <top (required)>'
2) User pages signup with invalid information after submission
Failure/Error: before { click_button submit }
ActionController::ParameterMissing:
param not found: user
# ./app/controllers/users_controller.rb:61:in `user_params'
# ./app/controllers/users_controller.rb:21:in `create'
# ./spec/requests/user_pages_spec.rb:93:in `block (5 levels) in <top (required)>'
3) User pages signup with invalid information after submission
Failure/Error: before { click_button submit }
ActionController::ParameterMissing:
param not found: user
# ./app/controllers/users_controller.rb:61:in `user_params'
# ./app/controllers/users_controller.rb:21:in `create'
# ./spec/requests/user_pages_spec.rb:93:in `block (5 levels) in <top (required)>'
4) User pages signup with valid information should create a user
Failure/Error: before { valid_signup(user) }
Capybara::ElementNotFound:
Unable to find field "Name"
# ./spec/support/utilities.rb:10:in `valid_signup'
# ./spec/requests/user_pages_spec.rb:102:in `block (4 levels) in <top (required)>'
5) User pages signup with valid information after saving the user
Failure/Error: before { valid_signup(user) }
Capybara::ElementNotFound:
Unable to find field "Name"
# ./spec/support/utilities.rb:10:in `valid_signup'
# ./spec/requests/user_pages_spec.rb:102:in `block (4 levels) in <top (required)>'
6) User pages signup with valid information after saving the user
Failure/Error: before { valid_signup(user) }
Capybara::ElementNotFound:
Unable to find field "Name"
# ./spec/support/utilities.rb:10:in `valid_signup'
# ./spec/requests/user_pages_spec.rb:102:in `block (4 levels) in <top (required)>'
7) User pages signup with valid information after saving the user
Failure/Error: before { valid_signup(user) }
Capybara::ElementNotFound:
Unable to find field "Name"
# ./spec/support/utilities.rb:10:in `valid_signup'
# ./spec/requests/user_pages_spec.rb:102:in `block (4 levels) in <top (required)>'
Finished in 9.1 seconds
119 examples, 7 failures
Failed examples:
rspec ./spec/requests/user_pages_spec.rb:88 # User pages signup with invalid information should not create a user
rspec ./spec/requests/user_pages_spec.rb:95 # User pages signup with invalid information after submission
rspec ./spec/requests/user_pages_spec.rb:96 # User pages signup with invalid information after submission
rspec ./spec/requests/user_pages_spec.rb:104 # User pages signup with valid information should create a user
rspec ./spec/requests/user_pages_spec.rb:113 # User pages signup with valid information after saving the user
rspec ./spec/requests/user_pages_spec.rb:115 # User pages signup with valid information after saving the user
rspec ./spec/requests/user_pages_spec.rb:116 # User pages signup with valid information after saving the user
So Here's my user_pages_spec.rb:
require 'spec_helper'
describe "User pages" do
subject { page }
describe "index" do
let(:user) { FactoryGirl.create(:user) }
before do
sign_in user
visit users_path
end
it { should have_title('All users') }
it { should have_content('All users') }
describe "pagination" do
before(:all) { 30.times { FactoryGirl.create(:user) } }
after(:all) { User.delete_all }
it { should have_selector('div.pagination') }
it "should list each user" do
#User.all.each do |user|
User.paginate(page: 1).each do |user|
expect(page).to have_selector('li', text: user.name)
end
end
end
describe "delete links" do
it { should_not have_link('delete') }
describe "as an admin user" do
let(:admin) { FactoryGirl.create(:admin) }
before do
sign_in admin
visit users_path
end
it { should have_link('delete', href: user_path(User.first)) }
it "should be able to delete another user" do
expect do
click_link('delete', match: :first)
end.to change(User, :count).by(-1)
end
it { should_not have_link('delete', href: user_path(admin)) }
end
end
end
describe "profile page" do
let(:user) { FactoryGirl.create(:user) }
let!(:m1) { FactoryGirl.create(:micropost, user: user, content: "Foo") }
let!(:m2) { FactoryGirl.create(:micropost, user: user, content: "Bar") }
before { visit user_path(user) }
it { should have_content(user.name) }
it { should have_title(user.name) }
describe "microposts" do
it { should have_content(m1.content) }
it { should have_content(m2.content) }
it { should have_content(user.microposts.count) }
end
end
describe "signup page" do
before { visit signup_path }
it { should have_content('Sign up') }
it { should have_title(full_title('Sign up')) }
end
describe "signup" do
before { visit signup_path }
let(:submit) { "Create my account" }
describe "with invalid information" do
it "should not create a user" do
expect { click_button submit }.not_to change(User, :count)
end
describe "after submission" do
before { click_button submit }
it { should have_title('Sign up') }
it { should have_content('error') }
end
end
describe "with valid information" do
let(:user) {FactoryGirl.build(:user)}
before { valid_signup(user) }
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "after saving the user" do
before { click_button submit }
#let(:user) { User.find_by(email: 'user#example.com') }
it { should have_title(user.name) }
#it { should have_selector('title', text: user.name) }
it { should have_selector('div.alert.alert-success', text: 'Welcome') }
it { should have_link('Sign out') }
end
end
end
describe "edit" do
let(:user) { FactoryGirl.create(:user) }
before do
sign_in user
visit edit_user_path(user)
end
describe "page" do
it { should have_content("Update your profile") }
it { should have_title("Edit user") }
it { should have_link('Change', href: 'http://gravatar.com/emails') }
end
describe "with invalid information" do
before { click_button "Save changes" }
it { should have_content('error') }
end
describe "with valid information" do
let(:new_name) { "New Name" }
let(:new_email) { "new#example.com" }
before do
fill_in "Name", with: new_name
fill_in "Email", with: new_email
fill_in "Password", with: user.password
fill_in "Confirm Password", with: user.password
click_button "Save changes"
end
it { should have_title(new_name) }
it { should have_selector('div.alert.alert-success') }
it { should have_link('Sign out', href: signout_path) }
specify { expect(user.reload.name).to eq new_name }
specify { expect(user.reload.email).to eq new_email }
end
describe "forbidden attributes" do
let(:params) do
{ user: {admin: true, password: user.password, password_confirmation: user.password } }
end
before do
sign_in user, no_capybara: true
patch user_path(user), params
end
specify { expect(user.reload).not_to be_admin }
end
end
end
users_controller.rb:
class UsersController < ApplicationController
before_action :signed_in_user, only: [:index, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
before_filter :signed_in_user_filter, only: [:new, :create]
def index
#users = User.paginate(page: params[:page])
end
def show
#user = User.find(params[:id])
#microposts = #user.microposts.paginate(page: params[:page])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
sign_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
def destroy
#user = User.find(params[:id])
if current_user == #user
flash[:error] = "You must not delete yourself."
#redirect_to users_path
else
#user.destroy
flash[:success] = "User deleted."
#redirect_to users_url
end
redirect_to users_path
end
def edit
##user = User.find(params[:id])
end
def update
##user = User.find(params[:id])
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
#Before filters
def signed_in_user
unless signed_in?
store_location
redirect_to signin_url, notice: "Please sign in."
end
end
def signed_in_user_filter
redirect_to root_path, notice: "Already logged in" if signed_in?
end
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
end
I'm not sure what else would be releveant but here's app/views/users/new.html.erb:
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.submit "Create my account", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
To be honest I'm not 100% sure where to look for this problem. It just happened with these latest changes I've made in this chapter. I try to do all the exercises so sometimes there's variation in what I'm supposed to edit so I don't know if I've messed something up or perhaps just done something dumb. When I visit the app from a browser, and click the "Sign me up" link to register a new user I get the red rails error page that says ActionController::ParameterMissing in UsersController#create but I don't know exactly what that means. I didn't really think I changed any code that would affect that, but I've tinkered around with some stuff to try to complete previous exercises so perhaps that's whats happening.
Thanks for any help! This is my first SO post so hopefully I didn't make a huge mistake in etiquette/formatting. I searched for someone with similar problems, as usual, but couldn't find anything.
Edit: I wanted to add that I've been working off the previous version of this tutorial as I wasn't done when the new edition came out. You can find it here: http://rails-4-0.railstutorial.org/book/user_microposts
I think the answer is pretty simple. It looks like you deleted all of the fields out of your form when he only wanted you to add in the error rendering component. Your sign-up form should be something like:
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Create my account", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
I am attempted to display the next three future events from my database but the code below displays nothing. I can't see what I have done wrong.
This is the event controller:
class EventsController < ApplicationController
def show
#event = Event.where(:slug => params[:slug]).first
#future_events = Event.where('end_date > ?', Date.today).order('end_date ASC').limit(3)
General.first.get_blog
General.first.get_twitter
if #event.nil?
#event = Event.first
end
#days = [
{ speakers: #event.sessions.day1_speakers, workshops: #event.sessions.day1_workshops },
{ speakers: #event.sessions.day2_speakers, workshops: #event.sessions.day2_workshops }
]
end
end
And this is the event view:
<% #future_events.first(3).each do |e | %>
<div class="fourcol aboutColumn">
<h3><%= e.title %></h3>
<p><%= e.start_date.strftime("%e %B %Y") %>, <%= e.venue_title %></p>
<p><%= e.event_description %></p>
</div>
<% end %>
You should structure your query to return only the events you need:
Event.where('end_date > ?', Date.today).order('end_date ASC').limit(3)
Beyond that, I can't see why nothing is displayed. Can you post your entire controller method?
Update:
This is the equivalent query for Mongoid:
Event.where(:end_date.gt => Date.today).sort(:end_date => 1).limit(3)